四大组件之Content Provider

预热:动态申请权限

  • 调用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
     * vnd.android.cursor.item for a single record,
     * or vnd.android.cursor.dir/ for multiple items.
     * This method can be called from multiple threads, as described in
     * Processes
     * and Threads.
     *
     * 

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)