一、构造一个自己的Provider实现App之间数据共享
1、我们先来了解一下 Uri(统一资源定位符)
定义:每一个Content Provider使用一个公开的URI唯一标示其数据集,android所提供的ContentProvider都存放android.provider包中
结构:分为A、B、C、D四个部分
A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;
B:URI 的标识,唯一标识ContentProvider,外部调用者可以根据这个标识来找到它。为了保证URI标识的唯一性,它必须是一个完整的、小写的类名。一般是定义该ContentProvider的包.类的名称
C:路径(path),通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就可以了;
D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; "content://com.gdnf.provider/tablename/#" #表示数据id。
路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
1、要操作person表中id为10的记录,可以构建这样的路径:/person/10
2、要操作person表中id为10的记录的name字段,
person/10/name
3、要操作person表中的所有记录,可以构建这样的路径:/person
4、当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
5、如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:Uri
uri
= Uri.parse("content://com.bing.provider.personprovider/person")
2、UriMatcher
UriMatcher主要用在ContentProvider中,用来构建URI匹配项和判断Uri的正确性,如在insert之前先判断用户传进来的Uri是否与UriMatcher定义的匹配。
3、ContentUris
Long id=ContentUris.parseId(uri);取出URI中传递的ID
Uri uri=ContentUris.withAppendedId(uri,id);为Uri追加ID
4、案例代码
package com.example.provider; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.net.Uri; import android.support.annotation.Nullable; import com.example.dao.StuDao; /** * Created by Administrator on 2017/12/18. */ public class StuProvider extends ContentProvider { //定义authorities--这是表示Uri的“B部分”,获取ContentProvider的包名 private static final String authorities="com.example.provider.stuprovider"; //构建UriMatcher对象(用于管理和匹配Uri) private static UriMatcher matcher=new UriMatcher(UriMatcher.NO_MATCH); //为每一个Uri定义一个编码 //所有Stu的编码为1 private static final int STUS=1; //一个Stu的编码为2 private static final int STU=2; //根据姓名查找Stu的编码为3 private static final int STU_NAME=3; //根据性别查找Stu的编码为4 private static final int STU_SEX=4; //应用UriMatcher对象构建Uri匹配项 static{ //A部分默认为:content:。只需带入B、C、D的值 matcher.addURI(authorities,"/stu",STUS); matcher.addURI(authorities,"/stu/#",STU); matcher.addURI(authorities,"/stu/#/name",STU_NAME); matcher.addURI(authorities,"/stu/#/sex",STU_SEX); } //声明上下文 private Context context; @Override public boolean onCreate() { context=getContext(); return false; } @Nullable @Override public String getType(Uri uri) { if(matcher.match(uri)==STUS){ return "vnd.android.cursor.dir/stu"; }else if(matcher.match(uri)==STU){ return "vnd.android.cursor.item/stu"; } return null; } @Nullable @Override public Uri insert(Uri uri, ContentValues contentValues) { if(matcher.match(uri)==STUS){ long id=new StuDao(context).addStu(contentValues);//添加学生 Uri newUri=ContentUris.withAppendedId(uri,id); //发生了数据变化,给出一个通知信号 getContext().getContentResolver().notifyChange(uri,null); return newUri; } return null; } @Override public int delete(Uri uri, String s, String[] strings) { StuDao dao=new StuDao(context); switch (matcher.match(uri)){ case STUS: dao.delete("tb_stu",null,null); break; case STU: long id=ContentUris.parseId(uri);//从Uri里面解析出Id dao.delete("tb_stu","_id="+id,null); break; } //发生了数据编号,给出一个通知信号 getContext().getContentResolver().notifyChange(uri,null); return 0; } @Override public int update(Uri uri, ContentValues contentValues, String s, String[] strings) { StuDao dao=new StuDao(context); int i=-1; switch (matcher.match(uri)){ case STUS: i=dao.update("tb_stu",contentValues,s,strings); break; case STU: long id=ContentUris.parseId(uri);//从Uri里面解析出Id i=dao.update("tb_stu",contentValues,"_id="+id,null); break; } //发生了数据编号,给出一个通知信号 getContext().getContentResolver().notifyChange(uri,null); return 0; } @Nullable @Override public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) { StuDao dao=new StuDao(context); Cursor cursor=null; switch (matcher.match(uri)){ case STUS: cursor=dao.queryStu(strings,s,strings1,null,null,s1,null); break; case STU: long id=ContentUris.parseId(uri);//从Uri里面解析出Id cursor=dao.queryStu(strings,"_id="+id,null,null,null,s1,null); break; } return cursor; } }
二、在另一个程序中如何使用ContentResolver内容解析器进行数据操作
1、ContentResolver操作ContentProvider中的数据
当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用getContentResolver()方法获取ContentResolver对象
2、监听ContentProvider中数据的变化
如果ContentProvider的访问者需要监听ContentProvider中的数据变化,可以注册一个观察者getContentResolver().registerContentObserver(uri,bool,observer)
3、数据提供者在数据发生改变时发出消息
getContent().getContentResolver().notifyChange(uri,null)
4、案例代码
package com.example.android_contentprover_test; import android.app.Activity; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.widget.Toast; public class MainActivity extends Activity { //定义一个ContentResolver内容解析器 private ContentResolver resolver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //获取系统的ContentResolver对象 resolver=getContentResolver(); //为resolver添加一个监听事件,监听数据是否发生变化 Uri uri=Uri.parse("content://com.example.provider.stuprovider/stu"); resolver.registerContentObserver(uri,true,new StuObServer(handler)); } //构建一个handler对象执行数据操作 private Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); if(msg.what==1){ //为所欲为 findStuList(null);//执行查询 } } }; //构建一个观察者类 private class StuObServer extends ContentObserver{ private Handler handler; public StuObServer(Handler handler) { super(handler); this.handler=handler; } //当发生改变时 @Override public void onChange(boolean selfChange) { super.onChange(selfChange); //监听到数据发生改变时,发出一个编号为1的消息 handler.sendEmptyMessage(1); } } public void addStu(View view){ //声明数据来源——路径 Uri addUri=Uri.parse("content://com.example.provider.stuprovider/stu"); //创建一个数据对象 ContentValues values=new ContentValues(); values.put("sname","Join"); values.put("sage",21); values.put("ssex","男"); //使用内容解析器执行添加(参数为:数据的来源,更改的数据) Uri newUri=resolver.insert(addUri,values); //通过解析器得到更改数据的ID long id= ContentUris.parseId(newUri); Toast.makeText(this, "添加学生成功,ID="+id, Toast.LENGTH_SHORT).show(); //使用内容解析器调用查询方法,查询数据 Cursor cursor=resolver.query(newUri,null,null,null,null); if(cursor.moveToNext()){ int _id=cursor.getInt(cursor.getColumnIndex("_id")); String name=cursor.getString(cursor.getColumnIndex("sname")); Toast.makeText(this, "ID="+_id+",Name="+name, Toast.LENGTH_SHORT).show(); } cursor.close(); } public void findStuList(View view){ Uri uri=Uri.parse("content://com.example.provider.stuprovider/stu"); Cursor cursor=resolver.query(uri,null,null,null,null); while(cursor.moveToNext()){ int _id=cursor.getInt(cursor.getColumnIndex("_id")); String name=cursor.getString(cursor.getColumnIndex("sname")); Log.i("App1 StuList", "ID="+_id+",Name="+name); } cursor.close(); } }