美文网首页
ContentProvider介绍与使用

ContentProvider介绍与使用

作者: 帝王鲨kingcp | 来源:发表于2018-04-02 19:42 被阅读0次

    ContentProvider、ContentResolver、ContentObserver三者之间的关系

    ContentProvider 内容提供者,用于对外提供数据 。
    ContentResolver 内容解析者,用于获取内容提供者提供的数据 。
    ContentObserver 内容监听器,可以监听数据的改变状态 。

    ContentProvider 是如何实现数据共享的

    第一步:需要创建一个类继承ContentProvider,实现相关方法。
    public class ContentProviderTest extends ContentProvider {
        @Override
        public boolean onCreate() {
            return false;
        }
    
        @Nullable
        @Override
        public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
            return null;
        }
    
         /**覆盖ContentProvider的getType方法对于用new Intent(String action, Uri uri)方法启动activity是很重要的,
            如果它返回的MIME type和activity在<intent filter>中定义的data的MIME type不一致,将造成activity无法启动。
          */
        @Nullable
        @Override
        public String getType(@NonNull Uri uri) {
            return null;
        }
    
        @Nullable
        @Override
        public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
            return null;
        }
    
        @Override
        public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
            return 0;
        }
    
        @Override
        public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
            return 0;
        }
    }
    
    第二步:在AndroidManifest.xml中注册ContentProvider,申明权限。

    android:exported="true",让外部应用可以访问
    android:authorities="com.king.qingpiao.contentProvider",申明URI中的authority

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.king.qiangpiao">
    
        <!-- 声明一个权限  -->
        <permission
            android:name="com.king.qiangpiao.PRIVATE.all"
            android:label="provider permission"
            android:protectionLevel="normal" />
        <permission
            android:name="com.king.qiangpiao.PRIVATE.read"
            android:label="provider read permission"
            android:protectionLevel="normal" />
        <permission
            android:name="com.king.qiangpiao.PRIVATE.write"
            android:label="provider write permission"
            android:protectionLevel="normal" />
    
        <application
            android:name=".MyApplication"
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <provider
                android:authorities="com.king.qiangpiao.contentProvider"
                android:name=".Book_ContentProvider"
                android:readPermission="com.king.qiangpiao.PRIVATE.read"
                android:writePermission="com.king.qiangpiao.PRIVATE.write"
                android:permission="com.king.qiangpiao.PRIVATE.all"
                android:exported="true">
            </provider>     
        </application>
    
    </manifest>
    
    第三步:在其他应用中通过ContentResolver获取想要的数据。同时也需要给访问ContentProvider的权限。

    需要使用ContentProvider的应用,必须在AndroidManifest.xml中添加ContentProvider中申明的权限。

    <uses-permission android:name="com.king.qiangpiao.PRIVATE.all"/>
    <uses-permission android:name="com.king.qiangpiao.PRIVATE.read"/>
    <uses-permission android:name="com.king.qiangpiao.PRIVATE.write"/>
    

    实例

    在A应用中的Book_ContentProvider ,对外提供应用数据。在query中用SQLiteQueryBuilder进行映射查询。
    其中getType方法对于用new Intent(String action, Uri uri)方法启动activity是很重要的,如果它返回的MIME type和activity在<intent filter>中定义的data的MIME type不一致,将造成activity无法启动。
    具体的是注册内容就是第二步中配置。

    public class Book_ContentProvider extends ContentProvider {
    
        private static final String TAG = "Book_ContentProvider";
        private static final String AUTHORITY = "com.king.qiangpiao.contentProvider";//在AndroidManifest.xml中注册authority
        private static final Uri BOOK_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/book");
        private static final Uri USER_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/user");
        private static Map projectionMap;//查询映射,防止外部应用知道真正SQLite中的列表名
        private Context mContext;
        private SQLiteDatabase mDb;
        private static final int BOOK_URI_CODE = 0;
        private static final int USER_URI_CODE = 1;
        private static final String BOOK_TABLE_NAME = "book";
        private static final String USER_TABLE_NAME = "user";
        //对URI的配对
        private static final UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        static {
            mUriMatcher.addURI(AUTHORITY,BOOK_TABLE_NAME,BOOK_URI_CODE);
            mUriMatcher.addURI(AUTHORITY,USER_TABLE_NAME,USER_URI_CODE);
        }
    
        @Override
        public boolean onCreate() {
            Log.i(TAG, "onCreate: Thread name = " + Thread.currentThread().getName());
            mContext = getContext();
            mDb = new DBHelper(mContext).getReadableDatabase();
            projectionMap = new HashMap<String,String>();
            projectionMap.put("book_id","_id");//外部 book_id 对应内部 _id
            projectionMap.put("book_name","name");//外部 book_name 对应内部 name
            return false;
        }
    
        @Nullable
        @Override
        public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
            //执行query , insert , delete , update是在不同的线程中的,有的操作需要注意这个问题
            Log.i(TAG, "query: Thread name = " + Thread.currentThread().getName());
            String table = getTableName(uri);
            if(table == null){
                throw new IllegalArgumentException("Unsupported URI: " + uri);
            }
            //通过映射查询
            SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
            queryBuilder.setTables(BOOK_TABLE_NAME);
            queryBuilder.setProjectionMap(projectionMap);
            return queryBuilder.query(mDb,projection,selection,selectionArgs,null,null,sortOrder);
        }
    
        @Nullable
        @Override
        public String getType(@NonNull Uri uri) {
            Log.i(TAG, "getType: Thread name = " + Thread.currentThread().getName());
            return null;
        }
    
        @Nullable
        @Override
        public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
            Log.i(TAG, "insert: Thread name = " + Thread.currentThread().getName());
            String table = getTableName(uri);
            if(table == null){
                throw new IllegalArgumentException("Unsupported URI: " + uri);
            }
            Log.i(TAG, "insert: table = " + table + " , values = " + values.toString());
            mDb.insert(table,null,values);
            mContext.getContentResolver().notifyChange(uri,null);//通知ContentObserver数据变化
            return uri;
        }
    
        @Override
        public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
            Log.i(TAG, "delete: Thread name = " + Thread.currentThread().getName());
            String table = getTableName(uri);
            if(table == null){
                throw new IllegalArgumentException("Unsupported URI: " + uri);
            }
            int count = mDb.delete(table,selection,selectionArgs);
            if(count > 0){
                mContext.getContentResolver().notifyChange(uri,null);//通知ContentObserver数据变化
            }
            return count;
        }
    
        @Override
        public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
            Log.i(TAG, "update: Thread name = " + Thread.currentThread().getName());
            String table = getTableName(uri);
            if(table == null){
                throw new IllegalArgumentException("Unsupported URI: " + uri);
            }
            int row = mDb.update(table,values,selection,selectionArgs);
            if(row > 0){
                mContext.getContentResolver().notifyChange(uri,null);//通知ContentObserver数据变化
            }
            return row;
        }
    
        //根据匹配返回数据库表名
        private String getTableName(Uri uri){
            int code = mUriMatcher.match(uri);
            String tableName = null;
            switch (code){
                case BOOK_URI_CODE:
                    tableName =  BOOK_TABLE_NAME;
                    break;
                case USER_URI_CODE:
                    tableName = USER_TABLE_NAME;
                    break;
            }
            return tableName;
        }
    }
    

    简单实现DBHelper,代码如下:

    public class DBHelper extends SQLiteOpenHelper {
    
        private static final String DB_NAME = "database.db";
        private static final String BOOK_TABLE_NAME = "book";
        private static final String USER_TABLE_NAME = "user";
        private static final int DB_VERSION = 1;
        private static final String CREATE_BOOK_TABLE = "CREATE TABLE IF NOT EXISTS " + BOOK_TABLE_NAME + "(_id INTEGER PRIMARY KEY," + "name TEXT)";
        private static final String CREATE_USER_TABLE = "CREATE TABLE IF NOT EXISTS " + USER_TABLE_NAME + "(_id INTEGER PRIMARY KEY," + "name TEXT)";
    
        public DBHelper(Context context) {
            super(context, DB_NAME, null, DB_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 newVersion) {
    
        }
    }
    

    应用B中,使用应用A的内容提供者,首先需要在应用B的AndroidManifest.xml中添加访问应用A的权限。

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.chenpeng.contentresolverproject">
    
        <uses-permission android:name="com.king.qiangpiao.PRIVATE.all"/>
        <uses-permission android:name="com.king.qiangpiao.PRIVATE.read"/>
        <uses-permission android:name="com.king.qiangpiao.PRIVATE.write"/>
        .....
    </manifest>
    

    接下来就是在应用B中如何使用ContentResolver

    public class MainActivity extends AppCompatActivity {
    
        private Button btn1,btn2,btn3,btn4,btn5;
        private ContentResolver mContentResolver;
        private Uri mBookUri,mUseUri;
        private static final String TAG = "MainActivity";
        private DatabaseContentObserver mContentObserver;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            btn1 = findViewById(R.id.btn1);
            btn2 = findViewById(R.id.btn2);
            btn3 = findViewById(R.id.btn3);
            btn4 = findViewById(R.id.btn4);
            btn5 = findViewById(R.id.btn5);
            //内容监听器
            mContentObserver = new DatabaseContentObserver(new Handler());
            //内容解析者
            mContentResolver = getContentResolver();
            //Uri地址 对应应用A中定义的authorities值
            mBookUri = Uri.parse("content://com.king.qiangpiao.contentProvider/book");
            mUseUri = Uri.parse("content://com.king.qiangpiao.contentProvider/user");
            //注册内容监听器
            mContentResolver.registerContentObserver(mBookUri,true,mContentObserver);
           
    
            //insert 插入数据到应用A中
            btn1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    ContentValues bookValues = new ContentValues();
                    bookValues.put("_id",1);
                    bookValues.put("name","NetEasy");
                    mContentResolver.insert(mBookUri,bookValues);
                    ContentValues userValues = new ContentValues();
                    userValues.put("_id",1);
                    userValues.put("name","DingLei");
                    mContentResolver.insert(mUseUri,userValues);
                }
            });
            //update 更新数据
            btn2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    ContentValues values = new ContentValues();
                    values.put("_id",1);
                    values.put("name","alibaba");
                    String[] selectionArgs = {String.valueOf(1)};
                    int count = mContentResolver.update(mBookUri,values,"_id = ?",selectionArgs);
                    Log.i(TAG, "update : " + count );
                }
            });
            //delete 删除数据
            btn3.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int raw = mContentResolver.delete(mUseUri,"_id = ?" , new String[]{String.valueOf(1)});
                    Log.i(TAG, "delete : " + raw );
                }
            });
            //query 查询
            btn4.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Cursor cursor = mContentResolver.query(mBookUri,new String[]{"book_id","book_name"},null,null,null);
                    while(cursor.moveToNext()){
                        int id = cursor.getInt(0);
                        String name = cursor.getString(1);
                        Log.i(TAG, "query: id = " + id + " , name = " + name);
                    }
                    cursor.close();
                }
            });
        }
    
        @Override
        protected void onDestroy() {
            //注销内容监听者
            mContentResolver.unregisterContentObserver(mContentObserver);
            super.onDestroy();
        }
    
    
        class DatabaseContentObserver extends ContentObserver{
    
            public DatabaseContentObserver(Handler handler) {
                super(handler);
            }
    
            @Override
            public void onChange(boolean selfChange) {
                Log.i(TAG, "onChange: book 数据变化" );
                super.onChange(selfChange);
            }
        }
    }
    
    

    送大家一句名言,自己理解。“No amount of anxiety makes any difference to anything that is going to happen.”

    相关文章

      网友评论

          本文标题:ContentProvider介绍与使用

          本文链接:https://www.haomeiwen.com/subject/bogdfftx.html