0119ContentProvider
0119ContentProvider 提供访问数据的一个统一的接口 在不同的应用程序之间共享数据
每一组数据都对应一个ContentProvider,有很多的ContentProvider 如何找到对应的ContentProvider? URL,统一资源标识符。对每一个资源起一个单独的名字,每一个ContentProvider都有一个公共的URL
Android所提供的ContentProvider都存放在Android.provider包当中 得到URL的一个常量,比如CONTENT_URL,得到这个常量就可以得到代表这个ContentProvider的URL,得到这个URL就使用这个ContentProvider提供的方法
得到ContentProvider后,根据其所提供的函数,可以增删改查
query() 查询 insert() 插入 update() 更新 delete() 删除 getType() 得到数据类型 onCreate() 创建时的回调函数?? 在创建ContentProvider时要做的一些事情
自己实现ContentProvider不多,但是如果不知道其工作原理,如何实现,用起来就会一头雾水
实现ContentProvider的过程
1,定义一个CONTENT_URI常量
2,定义一个类,继承ContentProvider
3,实现query,insert,update,delete,getType,onCreate方法
4,在AndroidManifest.xml当中进行声明
FirstContentProvider.java FirstContentProvider继承了ContentProvider这个类
FirstProviderMetaData.java定义了ContentProvider所需要使用的常量
首先定义一个CONTENT_URI 实际上是一个字符串,然后转换为URI类型,这个字符串必须是唯一的 content://com.example.codelab.transportationsprovider 第一,content:// 第二,需要完整的类名
需要有_id作为唯一的标示符 如果用SQLite _id可以定义为INTERGER PRIMARY KEY AUTOINCREMENT 即整形数据 关键字 自增长
数据类型 访问整张表的数据 "vnd.android.cursor.dir/vnd.firstprovider.user" dir是整张表格
如果要访问Provider里面其中一个数据的话 "vnd.android,cursor.item/vnd.firstprovider.user" item是其中一条数据
URIMatcher 作用 检测 URI是否符合我们的标准 原理是将一个URL和一个数字相关联
定义一个规则 uriMatcher.addURI(authority,目录路径,与之对应整型变量的值)//此为定义的一个规则 public String getType(Uri uri)方法中 uriMatcher.match(uri)进行匹配
UriMatcher就是起了一个规则,给每一个Uri一个整型变量 如果规则中“与之对应整型变量的值”与 case 匹配,则返还相应的值
定义一个 HashMap public static HashMap<String,String> userProjectionMap;//声明一个 HashMap static { userProjectionMap= new HashMap<String,String>(); userProjectionMap.put(UserTableMetaData._ID,UserTableMetaDate._ID); userProjectionMap.put(UserTableMetaData.USER_NAME,UserTableMetaDate.USER_NAME); }//给ContentProvider这张表的列起一个别名
getContentResolve();获得ContentResolve() ,这个可以操作ContentProvider
public Uri insert(要向哪一个Uri插入即向哪一个ContentProvider,值) //该函数的返回值是一个Uri,这个Uri表示的是刚刚使用这个函数所插入的数据 //content://mars.cp.FirstContentProvider/users/1 这个以代表新插入的行号 db.insert();该函数的返回值是新插入行的行号
SQLiteQueryBuilder qb=new SQLiteQueryBuilder();创建查询的语句,相当于一个查询语句
qb.appendWhere();//添加where字句
CPActivity.java
1 package com.example.test_cp; 2 3 import com.example.test_cp.FirstProviderMetaData.UserProvidermetaData; 4 5 import android.net.Uri; 6 import android.os.Bundle; 7 import android.app.Activity; 8 import android.content.ContentValues; 9 import android.database.Cursor; 10 import android.view.Menu; 11 import android.view.View; 12 import android.view.View.OnClickListener; 13 import android.widget.Button; 14 15 public class CPActivity extends Activity { 16 17 private Button myButton; 18 private Button myButton2; 19 @Override 20 protected void onCreate(Bundle savedInstanceState) { 21 super.onCreate(savedInstanceState); 22 setContentView(R.layout.activity_cp); 23 myButton=(Button)findViewById(R.id.myButton); 24 myButton2=(Button)findViewById(R.id.myButton2); 25 myButton.setOnClickListener(new MyButtonClickListener()); 26 myButton2.setOnClickListener(new MyButton2ClickListener()); 27 28 } 29 30 public class MyButtonClickListener implements OnClickListener{ 31 32 @Override 33 public void onClick(View v) { 34 // TODO Auto-generated method stub 35 ContentValues values=new ContentValues(); 36 //将张三这个值放到values 里面 键值对 37 values.put(FirstProviderMetaData.UserProvidermetaData.USER_NAME, "zhangsan"); 38 Uri uri=getContentResolver() 39 .insert(UserProvidermetaData.CONTENT_URI, values); 40 //这样就可以得到一个ContentResolver对象, 41 //可以操作ContentProvider,比如用ContentProvider里面的insert() 42 //把代表FirestContentProvider的uri传入,这样就可以调用FirstContentProvider的insert方法 43 System.out.println("uri--->"+uri.toString()); 44 } 45 46 } 47 48 public class MyButton2ClickListener implements OnClickListener{ 49 50 @Override 51 public void onClick(View v) { 52 // TODO Auto-generated method stub 53 Cursor c=getContentResolver().query(FirstProviderMetaData.UserProvidermetaData.CONTENT_URI, null, null, null, null); 54 while(c.moveToNext()){ 55 System.out.println(c.getString(c.getColumnIndex(UserProvidermetaData.USER_NAME))); 56 //getString里面是列的编号,列的编号要挺过getColumnIndex()得到; 57 } 58 } 59 60 } 61 62 63 64 }
FirstContentProvider.java
1 package com.example.test_cp; 2 import java.util.HashMap; 3 4 import com.example.mars_sqlite.db.DatebaseHelper;//引入另一个包 5 import com.example.test_cp.FirstProviderMetaData.UserProvidermetaData; 6 7 import android.content.ContentProvider; 8 import android.content.ContentUris; 9 import android.content.ContentValues; 10 import android.content.UriMatcher; 11 import android.database.Cursor; 12 import android.database.SQLException; 13 import android.database.sqlite.SQLiteDatabase; 14 import android.database.sqlite.SQLiteQueryBuilder; 15 import android.net.Uri; 16 import android.text.TextUtils; 17 18 public class FirstContentProvider extends ContentProvider{ 19 DatebaseHelper dh=null; 20 public static UriMatcher uriMatcher=null; 21 public static final int INCOMING_USER_COLLECTION=1; 22 public static final int INCOMING_USER_SINGLE=2; 23 /** 24 * URIMatcher 作用 检测 URI是否符合我们的标准 25 原理是将一个URL和一个数字相关联 26 */ 27 // 定义一个规则 28 static{ 29 uriMatcher=new UriMatcher(UriMatcher.NO_MATCH); 30 uriMatcher.addURI(FirstProviderMetaData.AUTHORITY, "users", INCOMING_USER_COLLECTION); 31 uriMatcher.addURI(FirstProviderMetaData.AUTHORITY, "users/#", INCOMING_USER_SINGLE); 32 } 33 34 public static HashMap<String,String> userProjectionMap; 35 static { 36 userProjectionMap=new HashMap<String,String>(); 37 userProjectionMap.put(UserProvidermetaData._ID, UserProvidermetaData._ID); 38 userProjectionMap.put(UserProvidermetaData.USER_NAME, UserProvidermetaData.USER_NAME); 39 //第一个是键,第二个是值,可以参考0113,老师讲师起别名 40 } 41 42 43 /** 44 * UriMatcher就是起了一个规则,给每一个Uri一个整型变量 45 * 如果规则中“与之对应整型变量的值”与 case 匹配,则返还相应的值 46 */ 47 //下面的代码这个实例没有用到没有 48 @Override 49 public String getType(Uri uri) { 50 // TODO Auto-generated method stub 51 52 switch(uriMatcher.match(uri)){ 53 case INCOMING_USER_COLLECTION: 54 return FirstProviderMetaData.UserProvidermetaData.CONTENT_TYPE; 55 case INCOMING_USER_SINGLE: 56 return FirstProviderMetaData.UserProvidermetaData.CONTENT_TYPE_ITEM; 57 default: 58 throw new IllegalArgumentException("Unknow String" + uri); 59 } 60 61 62 } 63 64 65 66 67 68 @Override 69 public Cursor query(Uri uri, String[] projection, String selection, 70 String[] selectionArgs, String sortOrder) { 71 //projection是列有哪些 72 //selcetion是where字句的内容 selectionArgs 前面查询的占位符所对应的参数 73 // TODO Auto-generated method stub 74 SQLiteQueryBuilder qb=new SQLiteQueryBuilder();//创建查询的语句,相当于一个查询语句 75 switch(uriMatcher.match(uri)){//要知道是查询的一系列的user对象还是单个的user对象 76 case INCOMING_USER_COLLECTION: 77 qb.setTables(UserProvidermetaData.TABLE_NAME);//设置要查询哪一张表格 78 qb.setProjectionMap(userProjectionMap); 79 //表格的每一列起一个别名projectionMap 80 break;//忘记添加这个导致进入第二个,get(1)不存在,得不到发生错误 81 //uri-->content://com.example.test_cp.FirstContentProvider/users所以进入第一个 82 case INCOMING_USER_SINGLE://这个没有进入 83 qb.setTables(UserProvidermetaData.TABLE_NAME); 84 qb.setProjectionMap(userProjectionMap); 85 //coneten://com.example.test_cp.FirstContentProvider/users/1 86 //users/1就是path部分 users是第0个元素 get(1)就是得到users/#中的# 87 qb.appendWhere(UserProvidermetaData._ID+"="+uri.getPathSegments().get(1)); 88 //相当于一个查询语句 89 default: 90 break; 91 92 93 } 94 95 String orderBy; 96 if(TextUtils.isEmpty(sortOrder))//如果传入的sortOrder是空的话 97 { 98 orderBy=UserProvidermetaData.DEFUALT_SORT_ORDER; 99 100 }else{orderBy=sortOrder;} 101 SQLiteDatabase db=dh.getWritableDatabase(); 102 Cursor c=qb.query(db, projection, selection, selectionArgs, null, null, sortOrder); 103 //0116 db要查询的数据库 projection 要查询的列 selection是where字句 selectionArgs是前面占位符对应的参数 104 c.setNotificationUri(getContext().getContentResolver(), uri);//通知修改 105 System.out.println("b"); 106 return c; 107 108 109 } 110 111 @Override 112 public boolean onCreate() { 113 // TODO Auto-generated method stub 114 dh=new DatebaseHelper(getContext(),FirstProviderMetaData.DATABASE_NAME); 115 //context 在你的环境中可以通过context得到运行环境的信息 116 return true; 117 } 118 119 120 121 122 @Override 123 public Uri insert(Uri uri, ContentValues values) { 124 // TODO Auto-generated method stub 125 SQLiteDatabase db=dh.getWritableDatabase(); 126 //向表中插入值 127 int rowid=(int)db.insert(FirstProviderMetaData.USERS_TABLE_NAME,null,values); 128 //该函数的返回值是新插入行的行号 129 if(rowid>0) 130 { 131 Uri insertedUserUri=ContentUris.withAppendedId(UserProvidermetaData.CONTENT_URI, rowid); 132 getContext().getContentResolver().notifyChange(uri,null );//通知数据的修改 133 return insertedUserUri;//返回新插入数据的uri 134 } 135 throw new SQLException("ERR Uri" + uri); 136 } 137 138 @Override 139 public int delete(Uri uri, String selection, String[] selectionArgs) { 140 // TODO Auto-generated method stub 141 return 0; 142 } 143 144 @Override 145 public int update(Uri uri, ContentValues values, String selection, 146 String[] selectionArgs) { 147 // TODO Auto-generated method stub 148 return 0; 149 } 150 151 }
FirstProviderMetaData.java
1 package com.example.test_cp; 2 3 import android.net.Uri; 4 import android.provider.BaseColumns; 5 6 public class FirstProviderMetaData{ 7 //要写完整的类名 8 public static final String AUTHORITY="com.example.test_cp.FirstContentProvider"; 9 //数据库名字,因为我们要用数据库来作为ContentProvider底层的存储方式 10 public static final String DATABASE_NAME="FirstProvider.db"; 11 //数据库版本 12 public static final int DATABASE_VERSION=1; 13 //表名 14 public static final String USERS_TABLE_NAME="users"; 15 //内部类,要实现的属性或者方法在接口中已经有,则可以定义一个内部类来实现此接口 16 public static final class UserProvidermetaData implements BaseColumns { 17 //BaseColumns定义了_ID 这个是The unique ID for a row 18 public static final String TABLE_NAME="users"; 19 //访问该provider的Uri , content+AUTHORTY+字表的名字 20 //表示取得这样一个ContentProvider的uri对象 21 public static final Uri CONTENT_URI=Uri.parse("content://"+AUTHORITY+"/users"); 22 //这个是定义访问整张表的数据类型,后面的名字可以随便起 23 public static final String CONTENT_TYPE="vnd.android.cursor.dir/vnd.firstprovider.user"; 24 //定义访问provider里面的某一条数据的数据类型 25 public static final String CONTENT_TYPE_ITEM="vnd.android.cursor.item/vnd.firstprovider.user"; 26 //列名,在users里面存放name这一列 27 public static final String USER_NAME="name"; 28 //定义默认排序 29 public static final String DEFUALT_SORT_ORDER="_id desc"; 30 } 31 32 }
DatabaseHelpr.java
1 //第一,getReadableDatabase(),getWritableDatabase()可以获得SQLiteDatabse对象,通过该对象可以对数据库进行操作 2 //即通过数据库助手类,可以通过他的两个函数得到可读或者可写的数据库对象 3 //第二,提供了onCreate()和onUpgrade()两个回调函数,允许我们在创建和升级数据库时,进行自己的操作 4 //自定义SQLiteOpenHelper,必需要实现onCreate(), onUpgrade(),可以选择实现onOpen。 5 package com.example.mars_sqlite.db; 6 7 import com.example.test_cp.FirstProviderMetaData; 8 import com.example.test_cp.FirstProviderMetaData.UserProvidermetaData; 9 10 import android.content.Context; 11 import android.database.sqlite.SQLiteDatabase; 12 import android.database.sqlite.SQLiteDatabase.CursorFactory; 13 import android.database.sqlite.SQLiteOpenHelper; 14 //A helper class to manage database creation and version management. 15 16 public class DatebaseHelper extends SQLiteOpenHelper 17 { 18 19 public DatebaseHelper(Context context, String name, CursorFactory factory, 20 int version) { 21 super(context, name, factory, version); 22 // TODO Auto-generated constructor stub 23 } 24 25 public DatebaseHelper(Context context,String name,int version) 26 27 { 28 this(context ,name ,null, version);//调用上面四个参数的构造函数 29 } 30 public DatebaseHelper(Context context,String name ) 31 { 32 this (context ,name ,1);//调用上面三个参数的构造函数 33 } 34 35 //下面函数要创建实际上是在第一次得到SQliteDatebase对象的时候才会调用这个方法, 36 //意思就是仅仅生成DatebaseHelper(继承SQliteOpenHelper)的对象是无法执行这两个函数, 37 //只有调用getReadableDatebase 和getWritableDatebase时候才会调用这些方法 38 @Override 39 public void onCreate(SQLiteDatabase db) { 40 // TODO Auto-generated method stub 41 System.out.println("create a datebase"); 42 //db.execSQL("create table user(id int,name verchar(20))"); 43 db.execSQL("create table"+" "+FirstProviderMetaData.USERS_TABLE_NAME+ 44 "("+UserProvidermetaData._ID+" "+"INTEGER PRIMARY KEY AUTOINCREMENT," + 45 UserProvidermetaData.USER_NAME+" "+"verchar(20));");//数据库db执行数据库语句 46 }//这里创建表名为user 47 //当更新这张表时候,要更改scheme version 即模式版本,不然无法更新 48 //Called when the database needs to be upgraded. 49 //The implementation should use this method to drop tables, 50 //add tables, or do anything else it needs to upgrade to the new schema version 51 @Override 52 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 53 // TODO Auto-generated method stub 54 System.out.println("onUpgrade a datebase"); 55 } 56 }
经过测试,以下语句必须添加在AndroidManifest.xml中
<provider
android:name="com.example.test_cp.FirstContentProvider"
android:authorities="com.example.test_cp.FirstContentProvider"
/>