四大組件之Content Provider

預(yù)熱:動態(tài)申請權(quán)限

  • 調(diào)用checkSelfPermission(String permission)方法檢查是否具有權(quán)限
  • 復(fù)寫onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 方法,來確認進入權(quán)限界面返回后是否獲取到了對應(yīng)權(quán)限。
  • 本文中,想要獲取到聯(lián)系人的內(nèi)容,則需要動態(tài)獲取Manifest.permission.CALL_PHONE的權(quán)限,同時Manifest里面要注冊該權(quán)限。

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讀取數(shù)據(jù) (跨程序調(diào)用數(shù)據(jù))

ContentResolver其實是對于外部數(shù)據(jù)庫的一個封裝,可以通過其Provider提供的接口來實現(xiàn)對外部數(shù)據(jù)的增刪改查。
實現(xiàn)readContacts()具體功能:讀取所有聯(lián)系人姓名及其電話號碼

    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();
        }
    }

創(chuàng)建ContentProvider供外部使用

1.總體使用方法(搭配前文的數(shù)據(jù)庫介紹的DBOpenHelper一起使用)

ContentProvider相當于對于創(chuàng)建的數(shù)據(jù)庫的對外部的一層封裝,外部應(yīng)用or模組想要對本數(shù)據(jù)庫進行操作的話,則必須通過ContentProvider來進行交互。ContentPorvider可以指定用戶可以訪問的uri,針對uri,在ContentPorvider里進行封裝好的處理動作,這樣就避免了敏感信息可以被外部訪問到,同時又把想要對外暴露的數(shù)據(jù)暴露了出來。

SampleCode, 這里僅針對query 進行了實現(xiàn)。其它幾個操作的流程是類似的

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);
        // *:匹配任意長度任意字符
        // #:匹配任意長度數(shù)字
        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.關(guān)于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中含有多條或是單條數(shù)據(jù),可以優(yōu)化處理邏輯,提高效率;具體分析詳見下方連接
對ContentProvider中g(shù)etType方法的一點理解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容