ContentProvider,ContentResolver和ContentObserver 使用
1 ContentProvider内容提供者
四大组件之一,实现不同程序实现数据的共享。联系人应用就使用了ContentProvider,比如你在自己的应用可以读取和修改联系人的数据(获得相应权限)。
其实它也是一个中间人,真正的数据源是文件或者SQLite。通过Uri向外暴露访问地址
2 ContentResolver内容解析者
一个应用通过ContentResolver可以访问另一个应用通过ContentProvider提供的数据(当然也可以在自己的应用中)。
3 ContentObserver内容观察者
监听数据库的变化,执行相应的操作。更新UI
mContentResolver.registerContentObserver(WicketProvider.CONTENT_URI, true, mChatObserver);
使用案例:
1 自定义StatusProvider
a 自定义数据库工具类
b 自定义StatusProvider继承ContentProvider 覆写对应的方法
创建,增删改查方法
package com.ecarx.systemui.plugin.statusbar.provider; import android.content.ContentProvider; import android.content.ContentValues; import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; import androidx.annotation.NonNull; import androidx.annotation.Nullable; public class StatusProvider extends ContentProvider { // 声明当前ContentProvider组件的唯一标识(Authority),注:必须使用小写字母 private static final String STATUSPROVIDER_AUTHORITY = "com.ecarx.systemui.plugin.statusbar.provider"; private String exitApp = ""; @Override public boolean onCreate() { return true; } @Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) { MatrixCursor cursor = new MatrixCursor(strings); cursor.addRow(new Object[]{exitApp}); return cursor; } @Nullable @Override public String getType(@NonNull Uri uri) { return null; } @Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) { exitApp = contentValues.getAsString("exitApp"); //need notifyChange getContext().getContentResolver().notifyChange(uri, null); return uri; } @Override public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) { exitApp = ""; return 0; } @Override public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) { return 0; } }
c 清单文件中配置provider
<provider
android:authorities="com.ecarx.systemui.plugin.statusbar.provider"
android:name=".statusbar.provider.StatusProvider"
android:enabled="true"
android:exported="true"/>
2 通过ContentResolver更新数据(ContentProvider所在进程或其他进程均可),触发ContentProvider提供的对应方法
private String statusbarProvider = "com.ecarx.systemui.plugin.statusbar.provider"; private Uri uri = Uri.parse("content://"+statusbarProvider); public void exitApp(String exitApp) { if("launcher".contains(exitApp) || "com.ecarx.systemui.plugin".contains(exitApp)){ return; } ContentValues values = new ContentValues(); values.put("exitApp",exitApp); Uri uriResult = mContentResolver.insert(uri,values); }
3 其他应用进程注册ContentObserver监听数据变化,更新UI
private Uri uri = Uri.parse("content://com.ecarx.systemui.plugin.statusbar.provider");
private void registerObeserver() {
Log.e(TAG, "registerObeserver");
getContentResolver().registerContentObserver(uri, true, observer);
}
ContentObserver observer = new ContentObserver(new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.e(TAG, "observer - onChange");
Cursor cursor = getContentResolver().query(uri, new String[]{"exitApp"}, null, null, null);
while (cursor.moveToNext()) {
String result = cursor.getString(0);
Log.e(TAG, "observer - result : " + result);
}
}
};
ContentResolver查询方法
1 public class MainActivity extends Activity{ 2 private TextView tv_info; 3 private ContentResolver resolver; 4 private Uri uri = Uri.parse("content://com.user.contentprovider.users/users"); 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 // TODO Auto-generated method stub 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.layout_main); 10 tv_info = (TextView)findViewById(R.id.tv_info); 11 resolver = getContentResolver(); 12 } 13 public void click(View v){ 14 switch (v.getId()) { 15 case R.id.bt_query: 16 //建表时的语句:create table t_user(_id integer primary key,uname,upass,money) 17 query();//调用自定义的查询所有数据的方法 18 break; 19 case R.id.bt_insert: 20 insert();//调用自定义的插入数据的方法 21 break; 22 case R.id.bt_update: 23 //请自行实现 24 break; 25 default: 26 break; 27 } 28 } 29 private void insert() { 30 //调用自定义的插入数据的方法(硬编码) 31 ContentValues values = new ContentValues(); 32 values.put("uname", "zhang"); 33 values.put("upass", "321"); 34 values.put("money", "99"); 35 Uri nUri = resolver.insert(uri, values);//sqlite会自动指定主键id 36 long newId = ContentUris.parseId(nUri);//获取新插入的id 37 Toast.makeText(this, ""+newId, 0).show(); 38 } 39 private void query() { 40 //自定义的查询所有数据的方法 41 Cursor c = resolver.query(uri , new String[]{"_id","uname","upass","money"}, null, null,null); 42 String text = ""; 43 while(c.moveToNext()){ 44 text +=c.getString(0)+","+c.getString(1)+","+c.getString(2)+","+c.getString(3)+"\n"; 45 } 46 tv_info.setText(text); 47 } 48 }
【备注:】
ContentProvider是单例模式的,当多个应用程序通过使用ContentResolver 来操作使用ContentProvider 提供的数据时,ContentResolver 调用的数据操作会委托给同一个ContentProvider 来处理。这样就能保证数据的一致性。
Cursor 游标,查询时返回的结果集
具体应用参考实际开发项目。
使用ContentProvider和ContentResolver时,是否可用第三方ORM数据库工具,如GreenDao操作数据库?
不建议使用。这两者是通过Uri来操作数据,而GreenDao是通过bean来操作数据库。
SQLiteDatabase 和 ContentResolver操作数据库api有所不同,前者操作对象为表,后者为Uri。