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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值