Android四大组件Activity、Service、BroadcastReceiver、ContentProvide
四、ContentProvide
1.什么是ContentProvide
ContentProvider是Android中提供的专门用于不同应用间数据交互和共享的组件。其本质上是一个标准化的数据管道,它屏蔽了底层的数据管理和服务等细节,以标准化的方式在Android 应用间共享数据、数据交互,跨进程通信。
2.使用方法
1、在当前应用自定义ContentProvider类
- 继承ContentProvider基类,实现ContentProvide的抽象方法,实现对数据的CRUD(create,retrieve,update,delete),还有onCreate和getType。
- onCreate(),该方法在ContentProvider创建后会被调用,当其他应用程序第一次访问ContentProvide时,该ContentProvider会被创建出来,并立即回调该onCreate方法
- getType(Uri uri), 返回 当前Uri所代表的数据的MIME类型。如果该Uri对应数据可能包括多条记录,那么MIME类型字符串应该以 vnd.android.cursor.dir/开头;如果该Uri对应的数据只包含一条记录,那么返回MIME类型字符串应该以vnd.android.cursor.item/开头。
public class MyContentProvide extends ContentProvider {
//这里的AUTHORITY就是我们在AndroidManifest.xml中配置的authorities
private static final String AUTHORITY = "com.test.MyProvider";
//匹配成功后的匹配码
private static final int MATCH_CODE = 100;
private static UriMatcher uriMatcher;
//数据改变后指定通知的Uri
private static final Uri NOTIFY_URI = Uri.parse("content://" + AUTHORITY );
static {
//匹配不成功返回NO_MATCH(-1)
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//添加我们需要匹配的uri
uriMatcher.addURI(AUTHORITY,"", MATCH_CODE);
}
@Override
public boolean onCreate() {
SQLiteDatabase db = this.getContext().openOrCreateDatabase("test_db.db3", Context.MODE_PRIVATE, null);
db.execSQL("create table tab(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)");
ContentValues values = new ContentValues();
values.put("name", "test");
db.insert("tab", "_id", values);
db.close();
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
int match = uriMatcher.match(uri);
if (match == MATCH_CODE){
SQLiteDatabase db = this.getContext().openOrCreateDatabase("test_db.db3", Context.MODE_PRIVATE, null);
Cursor c = db.query("tab", null, null, null, null, null,null);
return c;
}
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
return 0;
}
}
2、在AndroidManifest.xml中进行注册
- 属性name指定ContentProvide实现类的类名;
- 属性authorities是Uri标识,ContentProvide就是以这个Uri的形式对外提供数据,ContentResolve也是根据该Uri进行访问操作该应用的数据的,可以理解为网站的域名
- 属性exported指定是否对外暴露数据,只有为true时,其他应用才可以访问该应用的数据,默认值为true。
<provider android:name=".activity.MyContentProvide" android:authorities="com.test.MyProvider"/>
3、其他应用使用ContentResolver对数据进行CRUD操作
- 通过调用Content的 getContentResolver() 方法获取 ContentResolver对象实例,其实ContentResolver的作用类似于HttpClient,获取对象后就可以根据Uri对应用的数据进行CRUD操作了
public class MyContentResolver extends BaseActivity {
private ContentResolver resolver;
private Observer observer;
@Override
protected void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//获取ContentResolver对象
resolver = getContentResolver();
//获取Uri对象
Uri uri = Uri.parse("content://com.test.MyProvider");
//获取数据
Cursor c = resolver.query(uri, null, null, null, null);
c.moveToFirst();
for (int i = 0; i < c.getCount(); i++) {
int index = c.getColumnIndexOrThrow("name");
String src = c.getString(index);
Log.d("TAG", src);
c.moveToNext();
}
//注册ContentObserver监听数据的变化
observer = new Observer(new Handler());
resolver.registerContentObserver(uri, true,observer);
}
class Observer extends ContentObserver {
public Observer(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Toast.makeText(MyContentResolver.this,
"数据列表发生变化", Toast.LENGTH_SHORT).show();
//onchange 方法中添加Toast便于观察
}
}
@Override
protected void onDestroy() {
super.onDestroy();
resolver.unregisterContentObserver(observer);
}
}
3.其他相关类
-
Uri(Universal Resource Identifier)统一资源定位符
ContentResolver通过uri来定位自己要访问的数据,安卓隐式启动的过程中我们也是通过uri来定位我们需要打开的Activity并且可以在uri中传递参数
URI的格式如下:[scheme:][//host:port][path][?query]
单单看这个可能我们并不知道是什么意思,下面来举个栗子就一目了然了
URI:http://www.baidu.com:8080/wenku/jiatiao.html?id=123456&name=jack
scheme:根据格式我们很容易看出来scheme为http
host:www.baidu.com
port:就是主机名后面path前面的部分为8080
path:在port后面?的前面为wenku/jiatiao.html
query:?之后的都是query部分为 id=123456$name=jack
uri的各个部分在安卓中都是可以通过代码获取的,下面我们就以上面这个uri为例来说下获取各个部分的方法:
getScheme() :获取Uri中的scheme字符串部分,在这里是http
getHost():获取Authority中的Host字符串,即 www.baidu.com
getPost():获取Authority中的Port字符串,即 8080
getPath():获取Uri中path部分,即 wenku/jiatiao.html
getQuery():获取Uri中的query部分,即 id=15&name=du -
UriMatcher在ContentProvider 中注册URI,根据 URI 匹配 ContentProvider 中对应的数据表
该类主要提供了如下两个方法:
① public void addURI(String authority, String path, int code) 用于向UriMatcher注册Uri,其中参数authority与path组成一个Uri,参数code 是该Uri对应的标识码
② public int match(Uri uri) 根据前面注册的Uri返回其对应的标识码,如果在UriMatcher中找不到对应的Uri则返回-1 -
ContentObserver观察 Uri引起 ContentProvider 中的数据变化 & 通知外界(即访问该数据访问者)
1、继承 ContentObserver 实现 onChange方法
2、注册ContentObserver 内容观察者 registerContentObserver
3、当该URI的ContentProvider数据发生变化时,通知外界getContext().getContentResolver().notifyChange(uri, null);
4、解除观察者 getContentResolver().unregisterContentObserver(uri)。
4.应用场景
- 可以使用系统自带的ContentProvider,如音频、视频、图片、通讯录和短信
- 单一应用的数据存储,但一般情况是跨进程使用
- 多应用开发数据共享
网友评论