Android 面試 ContentProvider

ContentProvider 作爲四大組件之一,講道理工作中應該經常用到纔對,但是做了三年android 開發卻沒怎麼用,在之前啓動相機拍照的時候有用到FileProvider 去獲取圖片(android7.0之後獲取圖片文件的權限問題)。

ContentProvider 的使用 實現原理底層也是binder

1.繼承ContentProvider 實現方法,需要注意的是這幾個方法返回的都是Cursor 對象,另外它的方法都是在binder 線程池中執行的需要注意數據同步的問題,以及數據變更的時候需要通知 observer

2.manifest 註冊

  1)AUTHORYTY 包名+名稱(用來識別這個provider)

  2)exported 表示別的程序是否能夠訪問這個provider

  3)permission (可以加上自定義的讀寫權限)

3.使用的時候

   1.註冊數據更新的觀察者 ContentObserver

   2.getContentResolver.query(),insert,update....

   3.操作的時候是異步的會掛起當前線程屬於耗時操作,不要在主線程直接調用

   4.Uri uri = Uri.parse("content://"+AUTHORITY+"PATH");

 

自定義ContentProvider的簡單實現,只實現了一個查詢的方法,將集合封裝成cursor 返回,參照FileProvider

public class BookProvider extends ContentProvider {
    /**
     * ContentProvider
     * 注意:onCreate 是在主線程,query update insert delete
     * 都是在Binder 線程池 需要注意數據同步
     * 在數據更新之後可以通過contentProviderObserver更新
     */
    List<Book> books = new CopyOnWriteArrayList<>();//線程安全的集合

    private static final String AUTHORITY = "com.example.contentproviderdemo.BookProvider";
    private static final int BOOK_CODE = 0;
    private static final UriMatcher uriMatcher;
    private static final String TAG = BookProvider.class.getSimpleName();

    private static final String[] COLUMS = {"bookName", "bookId"};

    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, "BOOK", BOOK_CODE);
    }


    @Override
    public boolean onCreate() {
        initBookList();
        return false;
    }

    @androidx.annotation.Nullable
    @Override
    public Cursor query(@androidx.annotation.NonNull Uri uri, @androidx.annotation.Nullable String[] projection, @androidx.annotation.Nullable String selection, @androidx.annotation.Nullable String[] selectionArgs, @androidx.annotation.Nullable String sortOrder) {
        if (uriMatcher.match(uri) == BOOK_CODE) {
            //將集合封裝成cursor 返回
            MatrixCursor cursor = new MatrixCursor(COLUMS, 1);
            for (int i = 0; i < books.size(); i++) {
                Book book = books.get(i);
                cursor.addRow(new Object[]{book.getBookName(), book.getBookId()});
            }
            return cursor;
        }
        Log.i(TAG, "query: projection = " + Arrays.toString(projection) + "selection = " + selection);
        return null;
    }

    @androidx.annotation.Nullable
    @Override
    public String getType(@androidx.annotation.NonNull Uri uri) {
        Log.i(TAG, "getType: ");
        return null;
    }

    @androidx.annotation.Nullable
    @Override
    public Uri insert(@androidx.annotation.NonNull Uri uri, @androidx.annotation.Nullable ContentValues values) {
        Log.i(TAG, "insert: ");
        Objects.requireNonNull(getContext()).getContentResolver().notifyChange(uri, null);
        return null;
    }

    @Override
    public int delete(@androidx.annotation.NonNull Uri uri, @androidx.annotation.Nullable String selection, @androidx.annotation.Nullable String[] selectionArgs) {
        Log.i(TAG, "delete: ");
        Objects.requireNonNull(getContext()).getContentResolver().notifyChange(uri, null);
        return 0;
    }

    @Override
    public int update(@androidx.annotation.NonNull Uri uri, @androidx.annotation.Nullable ContentValues values, @androidx.annotation.Nullable String selection, @androidx.annotation.Nullable String[] selectionArgs) {
        Log.i(TAG, "update: ");
        Objects.requireNonNull(getContext()).getContentResolver().notifyChange(uri, null);
        return 0;
    }


    private void initBookList() {
        books.add(new Book("java", 0));
        books.add(new Book("sqlite", 1));
        books.add(new Book("kotlin", 2));
        books.add(new Book("c", 3));
        books.add(new Book("數據結構與算法", 4));
    }

}

 註冊manifest

   <!--自定義權限-->
    <permission android:name="providerReadPermission"/>
    <permission android:name="providerWritePermission"/>           

     <provider
            android:name=".BookProvider"
            android:authorities="com.example.contentproviderdemo.BookProvider"
            android:exported="true"
            android:readPermission="providerReadPermission"
            android:writePermission="providerWritePermission"
            ></provider>

 

 使用

  Uri uri = Uri.parse("content://" + AUTHORITY + "/BOOK");
        /**第二參數表示路徑後面的更改是否通知觀察者*/
        getContentResolver().registerContentObserver(uri, false, new ContentObserver(null) {
            @Override
            public void onChange(boolean selfChange) {
                super.onChange(selfChange);
                Log.i(TAG, "onChange: ");
            }
        });

        /*耗時操作,查詢的時候會掛起當前線程,不建議在主線程中使用*/
        Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        if (cursor != null) {
            while (cursor.moveToNext()) {
                Log.i(TAG, "book: " + cursor.getColumnName(0) + "=" + cursor.getString(0));
                Log.i(TAG, "book: " + cursor.getColumnName(1) + "=" + cursor.getString(1));
            }
        }
        cursor.close();
    }

輸出結果

 總結:

知識點1. uriMatcher.add()->UriMatcher.match() == match_code

          2.Uri uri = uri.parse("content://"+AUTHORITY+PATH);

          3.manifest註冊  athoryty+permission

獲取手機的聯繫人信息

 private void requestPermission() {
        if (PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_CONTACTS)) {
            ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.READ_CONTACTS}, 10001);
        } else {
            readContacts();
        }
    }

    private void readContacts() {
        Cursor cursor1 = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
        if (cursor1 != null) {
            while (cursor1.moveToNext()) {
                Log.i(TAG, cursor1.getColumnName(0) + " = " + cursor1.getString(0));
                Log.i(TAG, cursor1.getColumnName(1) + " = " + cursor1.getString(1));
            }
            cursor1.close();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 10001 && resultCode == RESULT_OK) {
            readContacts();
        }
    }

只要知道uri 可以輕鬆訪問ContentProvider 的信息->解析Cursor

FileProvider 的使用

https://blog.csdn.net/yyo201/article/details/80744100

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章