美文网首页
四大组件之Content Provider

四大组件之Content Provider

作者: Crane_FeiE | 来源:发表于2018-09-14 08:00 被阅读0次

    预热:动态申请权限

    • 调用checkSelfPermission(String permission)方法检查是否具有权限
    • 复写onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 方法,来确认进入权限界面返回后是否获取到了对应权限。
    • 本文中,想要获取到联系人的内容,则需要动态获取Manifest.permission.CALL_PHONE的权限,同时Manifest里面要注册该权限。

    SampleCode

    public class ContentProiderActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_content_proider);
            if(checkPermission()){
                //TODO do actions with permission
                readContacts();
            }else {
                requestPermissions(new String[]{Manifest.permission.CALL_PHONE}, 1);
            }
        }
    
        private void readContacts() {
        }
    
        private boolean checkPermission(){
            return checkSelfPermission(Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED;
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            switch (requestCode){
                case 1:
                    if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        readContacts();
                    } else {
                        Log.w("lyh", "permission not granted");
                    }
                    break;
                default:
                    break;
            }
        }
    }
    

    通过ContentResolver读取数据 (跨程序调用数据)

    ContentResolver其实是对于外部数据库的一个封装,可以通过其Provider提供的接口来实现对外部数据的增删改查。
    实现readContacts()具体功能:读取所有联系人姓名及其电话号码

        private void readContacts() {
            Cursor cursor;
            try {
                cursor = getContentResolver()
                        .query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                        null , null, null, null);
                if(cursor != null) {
                    //we get all contact info in this while loop, use this info to do further
                    while (cursor.moveToNext()) {
                        String contactName = cursor.getString(cursor.getColumnIndex
                                (ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                        String number = cursor.getString(cursor.getColumnIndex
                                (ContactsContract.CommonDataKinds.Phone.NUMBER));
                        Log.i("lyh", "name = " + contactName + ", number = " + number);
                    }
                }
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
        }
    

    创建ContentProvider供外部使用

    1.总体使用方法(搭配前文的数据库介绍的DBOpenHelper一起使用)

    ContentProvider相当于对于创建的数据库的对外部的一层封装,外部应用or模组想要对本数据库进行操作的话,则必须通过ContentProvider来进行交互。ContentPorvider可以指定用户可以访问的uri,针对uri,在ContentPorvider里进行封装好的处理动作,这样就避免了敏感信息可以被外部访问到,同时又把想要对外暴露的数据暴露了出来。

    SampleCode, 这里仅针对query 进行了实现。其它几个操作的流程是类似的

    public class MyProvider extends ContentProvider {
        public static final String AUTHORITY = "com.example.crane.myfirstline.provider";
        public static final int BOOK_DIR = 0;
        public static final int BOOK_ITEM = 1;
        public static final int CATEGORY_DIR = 2;
        public static final int CATEGORY_ITEM = 3;
        public static final int DB_VERSION = 1;
    
        private static UriMatcher uriMatcher;
    
        private MyLibraryDBHelper dbHelper;
    
        static {
            uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
            uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
            // *:匹配任意长度任意字符
            // #:匹配任意长度数字
            uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
            uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);
            uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);
    
        }
    
        @Override
        public boolean onCreate() {
            dbHelper = new MyLibraryDBHelper(getContext(), "library.db", null, DB_VERSION);
            return false;
        }
    
        @Nullable
        @Override
        public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            Cursor c = null;
            switch (uriMatcher.match(uri)) {
                case BOOK_DIR:
                    //query all data in table1
                    c = db.query("book", projection, selection, selectionArgs, null, null,  sortOrder);
                    break;
                case BOOK_ITEM:
                    //query sigle data in table1
                    String bookId = uri.getPathSegments().get(1);
                    c = db.query("book", projection, "id = ?", new String[] {bookId}, null, null,  sortOrder);
                    break;
                case CATEGORY_DIR:
                    break;
                case CATEGORY_ITEM:
                    break;
                default:
                    break;
            }
            return c;
        }
    
        @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;
        }
    
        @Nullable
        @Override
        public String getType(@NonNull Uri uri) {
            switch (uriMatcher.match(uri)) {
                case BOOK_DIR:
                    return "vnd.android.cusor.dir/" + AUTHORITY + ".book";
                case BOOK_ITEM:
                    return "vnd.android.cusor.item/" + AUTHORITY + ".book";
                case CATEGORY_DIR:
                    return "vnd.android.cusor.dir/" + AUTHORITY + ".category";
                case CATEGORY_ITEM:
                    return "vnd.android.cusor.item/" + AUTHORITY + ".category";
                default:
                    break;
            }
            return null;
        }
    }
    

    2.关于getType()方法的思考

    Google给的注释:

        /**
         * Implement this to handle requests for the MIME type of the data at the
         * given URI.  The returned MIME type should start with
         * <code>vnd.android.cursor.item</code> for a single record,
         * or <code>vnd.android.cursor.dir/</code> for multiple items.
         * This method can be called from multiple threads, as described in
         * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
         * and Threads</a>.
         *
         * <p>Note that there are no permissions needed for an application to
         * access this information; if your content provider requires read and/or
         * write permissions, or is not exported, all applications can still call
         * this method regardless of their access permissions.  This allows them
         * to retrieve the MIME type for a URI when dispatching intents.
         *
         * @param uri the URI to query.
         * @return a MIME type string, or {@code null} if there is no type.
         */
        public abstract @Nullable String getType(@NonNull Uri uri);
    

    也就是说,通过返回这个MIME类型的字符串,可以判断出来我们在使用ContentResolver进行查询时,返回的cursor中含有多条或是单条数据,可以优化处理逻辑,提高效率;具体分析详见下方连接
    对ContentProvider中getType方法的一点理解

    相关文章

      网友评论

          本文标题:四大组件之Content Provider

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