美文网首页
内容提供器

内容提供器

作者: C_G__ | 来源:发表于2019-04-26 15:35 被阅读0次

    Content Provider

    主要用于在不同App间共享数据。

    权限申请

    App中某些功能的执行需要申请Android系统权限,如打电话等。
    AndroidManifest.xml中可以申请权限。

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.bl.blandroidpro">
        <uses-permission android:name="android.permission.CALL_PHONE" />
    </manifest>
    

    Android权限机制

    Android 6.0之前安装app时,提示app需要获取某些权限,其中包括一些个人隐私相关,如地理位置等,但是这些app日常粘度很高,还不能不安,所以用户只能被迫同意安装。
    Android开发团队也意识到了这个问题,于是Android 6.0开始引入了运行时权限。但是安卓的权限很多,有上百个,如果让用户一个个授权也很繁琐,所以Android团队将权限分成两部分:普通权限危险权限。只有危险权限才需要用户授权。

    危险权限

    Android的危险权限 一共9组 24个。每个权限属于一个权限组,同意其中一个权限就同意了同组中的所有权限。

    • CALENDAR
      READ_CALENDAR
      WRITE_CALENDAR
    • CAMERA
    • CONTACTS
      READ_CONTACTS
      WRITE_CONTACTS
      GET_ACCOUNTS
    • LOCATION
      ACCESS_FINE_LOCATION
      ACCESS_COARSE_LOCATION
    • MICROPHONE
      RECORD_AUTIO
    • PHONE
      READ_PHONE_STATE
      CALL_PHONE
      READ_CALL_LOG
      WRITE_CALL_LOG
      ADD_VOICEMAIL
      USE_SIP
      PROCESS_OUTGOING_CALLS
    • SENSORS
      BODY_SENSORS
    • SMS
      SEND_SMS
      RECEIVE_SMS
      READ_SMS
      RECEIVE_WAP_PUSH
      RECEIVE_MMS
    • STORAGE
      READ_EXTERNAL_STORAGE
      WRITE_EXTERNAL_STORAGE

    运行时权限

    运行时权限就是app在安装时不需要授权,在运行时具体用到某些功能时,再由用户决定是否授权,程序不可以擅自做主。

    // 校验是否获取某权限
    if (ContextCompat.checkSelfPermission(this,
        Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
        // 没有获取则请求权限
        ActivityCompat.requestPermissions(this,
            new String[]{Manifest.permission.READ_CONTACTS}, 1);
    } else {
        // 已经获取权限则做相应业务
        readContacts();
    }
    
    @Override
    public void onRequestPermissionsResult(int requestCode,
                       @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 1:
                // 同意授权
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    readContacts();
    
                // 不同意授权
                } else {
                    Toast.makeText(this,
                                "You denied the permission", Toast.LENGTH_LONG).show();
                }
                break;
            default:
                break;
        }
    }
    

    访问其他app的数据

    ContentResolver 通过该类访问其它app的数据。该类提供了CRUD操作的相关方法。以Uri作为参数。

    • insert() 插入数据
    • update() 修改数据
    • delete() 删除数据
    • query() 查询数据

    Uri参数格式及组成结构
    path结尾表示访问该表所有数据
    id结尾表示仅访问此条数据
    '*':匹配任意长度字符
    '#':匹配任意长度数字

    • scheme 协议
    • authority 区分应用程序,以包名命名。
    • path 对同一应用不同表做区分。
    • id 对同一表下的记录做区分
    // path结尾
    Uri uri = Uri.parse("content://com.example.app.provider/table1");
    // id结尾
    Uri uri = Uri.parse("content://com.example.app.provider/table2/1");
    // path *
    "content://com.example.app.provider/*";
    // id #
    "content://com.example.app.provider/table2/#";
    
    // 查询是通过query方法返回的游标,逐行按字段获取想要的信息
    // 获取联系人列表
    private void readContacts() {
            Cursor cursor = null;
            try {
                // 查询
                cursor = getContentResolver().query(
                        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                        null, null, null, null);
                if (cursor != null) {
                    // 移动到下一条
                    while (cursor.moveToNext()) {
                        // 获取联系人名
                        String disName = cursor.getString(cursor.getColumnIndex(
                                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
                        ));
                        // 获取联系人号码
                        String number = cursor.getString(cursor.getColumnIndex(
                                ContactsContract.CommonDataKinds.Phone.NUMBER
                        ));
                        contactList.add(disName + "\n" + number);
                    }
                    // 刷新列表
                    adapter.notifyDataSetChanged();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (cursor != null) {
                    // 关闭游标
                    cursor.close();
                }
            }
    }
    

    自定义内容提供器

    需要继承ContentProvider类,重写其中6个方法

    • onCreate()
    • query()
    • insert()
    • update()
    • delete()
    • getType() 获取MIME类型
      MIME类型由3部分组成
    • 必须以vnd开头
    • 以path结尾,后接 android.cursor.dir/, 以id结尾android.cursor.item/
    • 最后接上vnd.'authority'.'path'
    // path结尾
    vnd.android.cursor.dir/vnd.com.exxample.app.provider.table1
    // id结尾
    vnd.android.cursor.item/vnd.com.exxample.app.provider.table2
    

    示例代码


    MyContentProvider.java

    public class MyContentProvider extends ContentProvider {
    
        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 String URI_BOOK;
        public static String URI_CATEGORY;
    
        private static final String AUTHORITY = "com.bl.blandroidpro.provider";
        private static final String DB_NAME = "BookStore.db";
        private static final String PREFIX_CONTENT = "content://";
        private static final String SURFIX_BOOK = "book";
        private static final String SURFIX_BOOK_ID = "book/#";
        private static final String SURFIX_BOOK_TABLE = "Book";
        private static final String SURFIX_CATEGORY = "category";
        private static final String SURFIX_CATEGORY_ID = "category/#";
        private static final String SURFIX_CATEGORY_TABLE = "Category";
    
        private static final String VND_BOOK_DIR =
                "vnd.android.cursor.dir/vnd.com.bl.blandroidpro.provider.book";
        private static final String VND_BOOK_ITEM =
                "vnd.android.cursor.item/vnd.com.bl.blandroidpro.provider.book";
        private static final String VND_CATEGORY_DIR =
                "vnd.android.cursor.dir/vnd.com.bl.blandroidpro.provider.category";
        private static final String VND_CATEGORY_ITEM =
                "vnd.android.cursor.item/vnd.com.bl.blandroidpro.provider.category";
    
        private static UriMatcher sUriMatcher;
        private MyDatabaseHelper dbHelper;
    
        static {
            sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
            sUriMatcher.addURI(AUTHORITY, SURFIX_BOOK, BOOK_DIR);
            sUriMatcher.addURI(AUTHORITY, SURFIX_BOOK_ID, BOOK_ITEM);
            sUriMatcher.addURI(AUTHORITY, SURFIX_CATEGORY, CATEGORY_DIR);
            sUriMatcher.addURI(AUTHORITY, SURFIX_CATEGORY_ID, CATEGORY_ITEM);
    
            URI_BOOK = PREFIX_CONTENT + AUTHORITY + "/" + SURFIX_BOOK;
            URI_CATEGORY = PREFIX_CONTENT + AUTHORITY + "/" + SURFIX_CATEGORY;
        }
    
        public MyContentProvider () {
        }
    
        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            int deleteRows = 0;
            switch (sUriMatcher.match(uri)) {
                case BOOK_DIR:
                    deleteRows = db.delete(SURFIX_BOOK_TABLE, selection, selectionArgs);
                    break;
                case BOOK_ITEM:
                    String bookId = uri.getPathSegments().get(1);
                    deleteRows = db.delete(SURFIX_BOOK_TABLE,
                            "id = ?", new String[]{bookId});
                    break;
                case CATEGORY_DIR:
                    deleteRows = db.delete(SURFIX_CATEGORY_TABLE, selection, selectionArgs);
                    break;
                case CATEGORY_ITEM:
                    String categoryId = uri.getPathSegments().get(1);
                    deleteRows = db.delete(SURFIX_CATEGORY_TABLE,
                            "id = ?", new String[]{categoryId});
                    break;
                default:
                    break;
    
            }
            return deleteRows;
        }
    
        @Override
        public String getType(Uri uri) {
            switch (sUriMatcher.match(uri)) {
                case BOOK_DIR:
                    return VND_BOOK_DIR;
                case BOOK_ITEM:
                    return VND_BOOK_ITEM;
                case CATEGORY_DIR:
                    return VND_CATEGORY_DIR;
                case CATEGORY_ITEM:
                    return VND_CATEGORY_ITEM;
            }
            return null;
        }
    
        @Override
        public Uri insert(Uri uri, ContentValues values) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            Uri uriReturn = null;
            switch (sUriMatcher.match(uri)) {
                case BOOK_DIR:
                case BOOK_ITEM:
                    long newBookId = db.insert(SURFIX_BOOK_TABLE, null, values);
                    uriReturn = Uri.parse(URI_BOOK + "/" + newBookId);
                    break;
                case CATEGORY_DIR:
                case CATEGORY_ITEM:
                    long newCategoryId = db.insert(SURFIX_CATEGORY_TABLE, null, values);
                    uriReturn = Uri.parse(URI_CATEGORY + "/" + newCategoryId);
                    break;
                default:
                    break;
    
            }
            return uriReturn;
        }
    
        @Override
        public boolean onCreate() {
            dbHelper = new MyDatabaseHelper(getContext(), DB_NAME, null, 2);
            return true;
        }
    
        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                            String[] selectionArgs, String sortOrder) {
            SQLiteDatabase db = dbHelper.getReadableDatabase();
            Cursor cursor = null;
            switch (sUriMatcher.match(uri)) {
                case BOOK_DIR:
                    cursor = db.query(SURFIX_BOOK_TABLE, projection, selection,
                            selectionArgs, null, null, sortOrder);
                    break;
                case BOOK_ITEM:
                    String bookId = uri.getPathSegments().get(1);
                    cursor = db.query(SURFIX_BOOK_TABLE, projection, "id = ?",
                            new String[]{bookId}, null, null, sortOrder);
                    break;
                case CATEGORY_DIR:
                    cursor = db.query(SURFIX_CATEGORY_TABLE, projection, selection,
                            selectionArgs, null, null, sortOrder);
                    break;
                case CATEGORY_ITEM:
                    String categoryId = uri.getPathSegments().get(1);
                    cursor = db.query(SURFIX_CATEGORY_TABLE, projection, "id = ?",
                            new String[]{categoryId}, null, null, sortOrder);
                    break;
                default:
                    break;
            }
            return cursor;
        }
    
        @Override
        public int update(Uri uri, ContentValues values, String selection,
                          String[] selectionArgs) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            int updateRows = 0;
            switch (sUriMatcher.match(uri)) {
                case BOOK_DIR:
                    updateRows = db.update(SURFIX_BOOK_TABLE, values, selection, selectionArgs);
                    break;
                case BOOK_ITEM:
                    String bookId = uri.getPathSegments().get(1);
                    updateRows = db.update(SURFIX_BOOK_TABLE, values,
                            "id = ?", new String[]{bookId});
                    break;
                case CATEGORY_DIR:
                    updateRows = db.update(SURFIX_CATEGORY_TABLE, values, selection, selectionArgs);
                    break;
                case CATEGORY_ITEM:
                    String categoryId = uri.getPathSegments().get(1);
                    updateRows = db.update(SURFIX_CATEGORY_TABLE, values,
                            "id = ?", new String[]{categoryId});
                    break;
                default:
                    break;
    
            }
            return updateRows;
        }
    }
    

    activity_content_provider.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".chapter07.ContentProviderCustomActivity"
        android:orientation="vertical">
    
        <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="vertical">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">
    
                <Button
                    android:id="@+id/btn_cpc_addbook"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="添加一本书" />
                <Button
                    android:id="@+id/btn_cpc_querybook"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="查询书籍" />
                <Button
                    android:id="@+id/btn_cpc_updatebook"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="修改一本书" />
                <Button
                    android:id="@+id/btn_cpc_deletebook"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="删除一本书" />
                <TextView
                    android:id="@+id/tv_cpc_info"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
            </LinearLayout>
        </ScrollView>
    
    </LinearLayout>
    

    ContentProviderActivity.java

    public class ContentProviderActivity extends AppCompatActivity {
    
        public String newId;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_content_provider);
    
            final TextView tv_cpc_info = findViewById(R.id.tv_cpc_info);
    
            // 添加书籍
            Button btn_cpc_addbook = findViewById(R.id.btn_cpc_addbook);
            btn_cpc_addbook.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    ContentValues values = new ContentValues();
                    values.put("name", "Book");
                    values.put("author", "BL");
                    values.put("pages", 308);
                    values.put("price", 38);
                    Uri uri = Uri.parse(MyContentProvider.URI_BOOK);
                    Uri newUri = getContentResolver().insert(uri, values);
    
                    newId = newUri.getPathSegments().get(1);
                    tv_cpc_info.setText(queryBooks());
                }
            });
            // 查询书籍
            Button btn_cpc_querybook = findViewById(R.id.btn_cpc_querybook);
            btn_cpc_querybook.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    tv_cpc_info.setText(queryBooks());
                }
            });
            // 修改书籍
            Button btn_cpc_updatebook = findViewById(R.id.btn_cpc_updatebook);
            btn_cpc_updatebook.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Uri uri = Uri.parse(MyContentProvider.URI_BOOK + "/" + newId);
                    ContentValues values = new ContentValues();
                    values.put("name", "Good Book");
                    values.put("author", "Andy");
                    values.put("pages", 400);
                    values.put("price", 40);
                    getContentResolver().update(uri, values, null, null);
                    tv_cpc_info.setText(queryBooks());
                }
            });
    
            // 删除书籍
            Button btn_cpc_deletebook = findViewById(R.id.btn_cpc_deletebook);
            btn_cpc_deletebook.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Uri uri = Uri.parse(MyContentProvider.URI_BOOK + "/" + newId);
                    getContentResolver().delete(uri, null, null);
                    tv_cpc_info.setText(queryBooks());
                }
            });
        }
    
        public String queryBooks() {
            StringBuilder sb = new StringBuilder();
            sb.append("书名    作者    页数    价格\n");
    
            Uri uri = Uri.parse(MyContentProvider.URI_BOOK);
            Cursor cursor = getContentResolver().query(uri,
                    null, null, null, null);
            if (cursor != null) {
                while (cursor.moveToNext()) {
                    String name = cursor.getString(
                            cursor.getColumnIndex("name"));
                    String author = cursor.getString(
                            cursor.getColumnIndex("author"));
                    int pages = cursor.getInt(
                            cursor.getColumnIndex("pages"));
                    double price = cursor.getDouble(
                            cursor.getColumnIndex("price"));
                    sb.append(name + "    " + author + "    " + pages + "    " + price + "\n");
                }
                cursor.close();
            }
            return sb.toString();
        }
    }
    

    相关文章

      网友评论

          本文标题:内容提供器

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