Android 开发艺术探索笔记(6)

网友投稿 272 2022-09-21

Android 开发艺术探索笔记(6)

IPC之ContentProvider

ContentProvider因为是Android提供不同应用间数据共享的方式,所以它天生就适合IPC,ContentProvider的底层实现就是Binder,但它的使用比AIDL简单的多。 系统预置了许多ContentProvider,比如通讯录信息,日程表信息,要跨进程访问只需通过ContentResolver的query、update、insert和delete方法即可。下面来讲讲它在IPC中的应用。

首先我们自定义一个Provider,叫BookProvider只需要继承ContentProvider类并实现其中的六个方法:onCreate、query、update、insert、delete、getType。getType就是返回一个Uri请求所对应的MIME类型(媒体类型比如图片、声音)。根据Binder的工作原理,onCreate被系统调用并启动于主线程,而其它的五个方法均被外界回调并运行在Binder线程池中。ContentProvider主要以表格的形式来组织数据,并且包含很多表,对每个表来说,它们都具有行和列的层次性。它还支持文件数据,比如图片视频。ContentProvider代码如下:

public class BookProvider2 extends ContentProvider private static final String TAG = "BookProvider"; @Override public boolean onCreate() { Log.d(TAG,"onCreate,current thread:" + Thread.currentThread().getName()); return true; } @Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { Log.d(TAG,"query,current thread:" + Thread.currentThread().getName()); return null; } @Nullable @Override public String getType(@NonNull Uri uri) { Log.d(TAG,"getType"); return null; } @Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { Log.d(TAG,"insert"); return null; } @Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { Log.d(TAG,"delete"); return 0; } @Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { Log.d(TAG,"update"); return 0; }}

接着来创建一个Activity来调用这个BookProvider2

public class ProviderActivity extends Activity @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Uri uri = Uri.parse("content://com.rikka.contentprovider1.BookProvider2"); getContentResolver().query(uri,null,null,null,null); getContentResolver().query(uri,null,null,null,null); getContentResolver().query(uri,null,null,null,null); }}

通过query方法去查询BookProvider2中的数据,其中Uri中的内容唯一标识了Provider,这就是Provider的authorities的值。 这里讲一下:ContentProvider中的的方法是隐式的,所以用一般上述代码的情况去调用并不会出现BookProvider中的log日志,因为它执行与别的线程之中。但里面的方法还是会实现的。也就是BooKProvider的调用实现成功。 2. 为了更好的管理BookProvider,我们需要一个数据库。代码如下:

package com.rikka.contentprovider1;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;public class DbOpenHelper extends SQLiteOpenHelper private static final String DB_NAME = "book_provider2.db"; public static final String BOOK_TABLE_NAME = "book"; public static final String USER_TABLE_NAME = "user"; private static final int DB_VERSION = 1; private String CREATE_BOOK_TABLE = "CREATE TABLE IF NOT EXISTS" + BOOK_TABLE_NAME + "( _id INTEGER PRIMARY KEY," + "name TEXT )"; private String CREATE_USER_TABLE = "CREATE TABLE IF NOT EXISTS" + USER_TABLE_NAME + "( _id INTEGER PRIMARY KEY," + "name TEXT," + "sex INT )"; public DbOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_BOOK_TABLE); db.execSQL(CREATE_USER_TABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int

这里写了一个数据库,我们将它用作BookProvider2管理的数据库,里面有两个表Book,User,用户如何来区分的去操作这两个表呢?答案是Uri和Uri_Code,ContentProvider会给每个表单独的设置Uri,Uri_Code并用UriMatcher的addUri来让他们关联,外界来访问数据的时候可以通过Uri,Uri关联Uri_Code来访问每个表的数据。 这时候BookProvider中这样加Uri和Code

public class BookProvider2 extends ContentProvider private static final String TAG = "BookProvider"; public static final String AUTHORITY = "com.rikka.contentprovider1.BookProvider2"; public static final Uri Book_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/book"); public static final Uri USER_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/user"); public static final int BOOK_URI_CODE = 0; //book的uri_code public static final int USER_URI_CODE = 1; //user的uri_code private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { sUriMatcher.addURI(AUTHORITY,"book",BOOK_URI_CODE); sUriMatcher.addURI(AUTHORITY,"user",USER_URI_CODE); }

上面为Book和User指定了Uri,Uri_code。这时候外界想操作数据了,他们传了个URI进来,我们通过解析这个URI来得到外界想要操作的表。

/** * 通过外界访问的Uri->Uri_Code->想要操作的表名 * @return public String getTableName(Uri uri){ String tableName = null; switch (sUriMatcher.match(uri)){ case BOOK_URI_CODE: tableName = DbOpenHelper.BOOK_TABLE_NAME; break; case USER_URI_CODE: tableName = DbOpenHelper.USER_TABLE_NAME; break; default: break; } return

这时候就可以进行CRUD操作了,首先修改query,先通过Uri找到想外界要操作的表,然后通过传递的参数来进行数据库查询:

private DbOpenHelper dbhelper; private SQLiteDatabase db; @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Log.d(TAG,"query,current thread:" + Thread.currentThread().getName()); String table = getTableName(uri); if(table == null){ throw new IllegalArgumentException("Unsupported URI:" + uri); } db = dbhelper.getWritableDatabase(); return db.query(table,projection,selection,selectionArgs,sortOrder,null,null); }

关于其他3个方法都涉及到数据源的改变,可以通过ContentResolver的notifyChange来通知外界当前ContentProvider的数据发生了改变。可以通过CotnentResolver的registerContentObserver来注册观察者,unregisterContentObserver来解除观察者。 接下来来添加数据

@Override public boolean onCreate() { Log.d(TAG,"onCreate,current thread:" + Thread.currentThread().getName()); mContext = getContext(); initProviderData(); return true; } private void initProviderData() { db = new DbOpenHelper(mContext).getWritableDatabase(); db.execSQL("delete from " + DbOpenHelper.BOOK_TABLE_NAME); db.execSQL("delete from " + DbOpenHelper.USER_TABLE_NAME); db.execSQL("insert into book values(3,'Android');" ); db.execSQL("insert into book values(4,'IOS');"); db.execSQL("insert into book values(5,'Html5');"); db.execSQL("insert into user values(1,'jake',1);"); db.execSQL("insert into user values(2,'jasmine',0);"); } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { Log.d(TAG,"update"); String table = getTableName(uri); if(table == null){ throw new IllegalArgumentException("Unsupported URI:" + uri); } int row = db.update(table,values,selection,selectionArgs); if(row > 0 ){ mContext.getContentResolver().notifyChange(uri,null); } return row; @Override public Uri insert(Uri uri, ContentValues values) { Log.d(TAG,"insert"); String table = getTableName(uri); if(table == null){ throw new IllegalArgumentException("Unsupported URI:" + uri); } db.insert(table,null,values); mContext.getContentResolver().notifyChange(uri,null); return uri; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { Log.d(TAG,"delete"); String table = getTableName(uri); if(table == null){ throw new IllegalArgumentException("Unsupported URI:" + uri); } int count = db.delete(table,selection,selectionArgs); if(count > 0){ getContext().getContentResolver().notifyChange(uri,null); } return

最后在Activity中去调用他们

public class ProviderActivity extends Activity @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Uri bookuri = Uri.parse("content://com.rikka.contentprovider1.BookProvider2/book"); ContentValues values = new ContentValues(); values.put("_id",6); values.put("name","RikkaOvO"); getContentResolver().insert(bookuri,values); Cursor bookCursor = getContentResolver().query(bookuri,new String[]{"_id","name"},null,null,null); while (bookCursor.moveToNext()){ Book book = new Book(); book.bookId = bookCursor.getInt(0); book.bookName = bookCursor.getString(1); Log.e(TAG,"query book :" + book.toString()); } bookCursor.close(); Uri useruri = Uri.parse("content://com.rikka.contentprovider1.BookProvider2/user"); Cursor userCursor = getContentResolver().query(useruri,new String[]{"_id","name","sex"},null,null,null); while (userCursor.moveToNext()){ User user = new User(); user.userId = userCursor.getInt(0); user.userName = userCursor.getString(1); user.isMale = userCursor.getInt(2); Log.e(TAG,"query uesr :"

接下来为Log结果

至此完成了自定义ContentProvider,一种IPC的实现方式。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:【排错】net::ERR_ABORTED 404
下一篇:文案来啦:适合12月31日朋友圈跨年的文案句子!
相关文章

 发表评论

暂时没有评论,来抢沙发吧~