zoukankan      html  css  js  c++  java
  • Android探索之ContentProvider熟悉而又陌生的组件

    前言:

        总结这篇文章之前我们先来回顾一下Android Sqlite数据库,参考文章:http://www.cnblogs.com/whoislcj/p/5506294.html,Android程序内部数据存储如果使用Sqlite数据库,那么Android 如何实现程序间数据共享?Android 提供了一种机制可以实现程序间的数据共享,它就是Android 四大组件之一ContentProvider,Android为存储和获取数据提供统一的接口,用于实现程序间数据共享,不要将其理解为数据库。

         为什么说是熟悉又陌生呢?因为我们经常使用到,Android内置的许多数据都是采用ContentProvider,比如图片,视频,音频,手机联系人等,至于陌生那是因为我很少自己去实现一个ContentProvider,今天我们重点是来实现一个自定义ContentProvider。

    ContentProvider类简介:

         1.) 我们一般要继承ContentProvider,那么要实现那些函数呢?
    • ContentProvider()   构造函数
    • onCreate()    创建数据时调用的回调函数
    • insert()      插入数据
    • delete()     删除数据
    • update()    更新数据
    • query()      查询数据
    • getType()  得到数据类型
       2.)URI简介:

         ContentProvider通过URI来访问数据执行增删改查的操作,一个完整的URI有 content://自定义ContentProvider/xxx数据库名称 

         我们先声明一个作用域:

        //访问URI作用域
        public static final String CONTENT_URI="com.whoislcj.testsqlite.personprovider";

        对应URI举例说明一下:

    • content://com.whoislcj.testsqlite.personprovider/person   返回person所以数据
    • content://com.whoislcj.testsqlite.personprovider/person/10 返回id为10的person数据
       3.)UriMatcher简介

           主要用于匹配Uri,为什么要匹配Uri呢?通过上面的Uri举例可以看出操作域不一样,对于执行一个delete、update、query来说我们要获取参数参数执行不能对应操作。

       使用:

      //定义一个UriMatcher类对象,用来匹配Uri的。
        private static final UriMatcher uriMatcher;
        //集合操作
        public static final int INCOMING_COLLECTION = 1;
        //单个ID操作
        public static final int INCOMING_SIGNAL = 2;
        static {
            //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
            uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
            //如果match()方法匹配com.whoislcj.testsqlite.personprovider/person路径,返回匹配码为1
            uriMatcher.addURI(CONTENT_URI, "person", INCOMING_COLLECTION);//添加需要匹配uri,如果匹配就会返回匹配码
            //如果match()方法匹配content://com.ljq.provider.personprovider/person/230路径,返回匹配码为2
            uriMatcher.addURI(CONTENT_URI, "person/#", INCOMING_SIGNAL);//#号为通配符
        }
    4.)ContentUris简介

          ContentUris是对URI的操作类,比如获取URI路径里的参数,或者给URI拼接一个参数

        举例说明:

    • long id = ContentUris.parseId(uri);//从uri中获取id
    • Uri rowUri = ContentUris.withAppendedId(uri, rowId);//uri追加id 生成该条数据完整的URI地址
      5.)ContentResolver简介   

           ContentResolver主要用于为外部程序提供增删改查的操作函数,也可以注册观察者来监听数据的变化。

     6.)自定义ContentProvider具体实现:
    public class PersonProvider extends ContentProvider {
        // DatabaseHelper操作句柄
        private DBHelper dbHelper;
        //访问URI
        public static final String CONTENT_URI="com.whoislcj.testsqlite.personprovider";
        // 数据集的MIME类型字符串则应该以vnd.android.cursor.dir/开头
        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person";
        // 单一数据的MIME类型字符串应该以vnd.android.cursor.item/开头
        public static final String CONTENT_TYPE_ITME = "vnd.android.cursor.item/person";
        //定义一个UriMatcher类对象,用来匹配Uri的。
        private static final UriMatcher uriMatcher;
        //集合操作
        public static final int INCOMING_COLLECTION = 1;
        //单个ID操作
        public static final int INCOMING_SIGNAL = 2;
        static {
            //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
            uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
            //如果match()方法匹配com.whoislcj.testsqlite.personprovider/person路径,返回匹配码为1
            uriMatcher.addURI(CONTENT_URI, "person", INCOMING_COLLECTION);//添加需要匹配uri,如果匹配就会返回匹配码
            //如果match()方法匹配content://com.ljq.provider.personprovider/person/230路径,返回匹配码为2
            uriMatcher.addURI(CONTENT_URI, "person/#", INCOMING_SIGNAL);//#号为通配符
        }
    
        public PersonProvider() {
        }
    
        /**
         * 回调函数,在ContentProvider创建的时候,就会运行
         * 作用获取操作用户的句柄
         */
        @Override
        public boolean onCreate() {
            //这里会调用 DBHelper的构造函数创建一个数据库;
            dbHelper = new DBHelper(getContext());
            return true;
        }
    
        /**
         * 执行插入数据函数
         *
         * @param uri
         * @param values
         * @return
         */
        @Override
        public Uri insert(Uri uri, ContentValues values) {
            //获取一个可写的数据库
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            //调用数据库的插入操作 也可以自己构造sql语句 执行  db.execSQL();相对比较麻烦
            long rowId = db.insert(DBHelper.TABLE_NAME, "", values);
            //判断是否插入成功
            if (rowId > 0) {
                Uri rowUri = ContentUris.withAppendedId(uri, rowId);//uri追加id 生成该条数据完整的URI地址
                getContext().getContentResolver().notifyChange(uri, null);
                return rowUri;
            }
            throw new SQLException("Failed to insert row" + uri);
        }
    
        /**
         * 删除数据操作
         *
         * @param uri
         * @param selection
         * @param selectionArgs
         * @return
         */
        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            //获取一个可写的数据库
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            int count = 0;
            switch (uriMatcher.match(uri)) {
                case INCOMING_COLLECTION:
                    //执行删除操作
                    count = db.delete(DBHelper.TABLE_NAME, selection, selectionArgs);
                    getContext().getContentResolver().notifyChange(uri, null);
                    break;
                case INCOMING_SIGNAL:
                    long id = ContentUris.parseId(uri);//从uri中获取id
                    String where = "id=" + id; // 删除指定id的记录
                    where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : ""; // 把其它条件附加上
                    count = db.delete(DBHelper.TABLE_NAME, where, selectionArgs);
                    getContext().getContentResolver().notifyChange(uri, null);
                    break;
                default:
                    throw new SQLException("Failed to delete row " + uri);
            }
            //关闭数据库
            db.close();
            return count;
        }
    
        /**
         * 更新数据操作
         *
         * @param uri
         * @param values
         * @param selection
         * @param selectionArgs
         * @return
         */
        @Override
        public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
            //获取一个可写的数据库
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            int count = 0;
            switch (uriMatcher.match(uri)) {
                case INCOMING_COLLECTION:
                    //执行更新数据
                    count = db.update(DBHelper.TABLE_NAME, values, selection, selectionArgs);
                    getContext().getContentResolver().notifyChange(uri, null);
                    break;
                case INCOMING_SIGNAL:
                    long id = ContentUris.parseId(uri);//从uri中获取id
                    String where = "id=" + id;    // 删除指定id的记录
                    where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : "";// 把其它条件附加上
                    //执行更新数据
                    count = db.update(DBHelper.TABLE_NAME, values, where, selectionArgs);
                    getContext().getContentResolver().notifyChange(uri, null);
                    break;
                default:
                    throw new SQLException("Failed to update row " + uri);
            }
            //关闭数据库
            db.close();
            return count;
        }
    
        /**
         * 查询操作
         *
         * @param uri
         * @param projection
         * @param selection
         * @param selectionArgs
         * @param sortOrder
         * @return
         */
        @Override
        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
            //获取一个可读的数据库
            SQLiteDatabase db = dbHelper.getReadableDatabase();
            Cursor cursor = null;
            switch (uriMatcher.match(uri)) {
                case INCOMING_COLLECTION:
                    //执行查询
                    cursor = db.query(DBHelper.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
                    break;
                case INCOMING_SIGNAL:
                    long id = ContentUris.parseId(uri);//从uri中获取id
                    String where = "id=" + id;    // 删除指定id的记录
                    where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : "";// 把其它条件附加上
                    cursor = db.query(DBHelper.TABLE_NAME, projection, where, selectionArgs, null, null, sortOrder);
                    break;
                default:
                    throw new SQLException("Failed to query " + uri);
            }
            return cursor;
        }
    
        /**
         * 该方法用于返回当前Url所代表数据的MIME类型。
         *
         * @param uri
         * @return
         */
        @Override
        public String getType(Uri uri) {
            switch (uriMatcher.match(uri)) {
                case INCOMING_COLLECTION:
                    return CONTENT_TYPE;
                case INCOMING_SIGNAL:
                    return CONTENT_TYPE_ITME;
                default:
                    throw new IllegalArgumentException("Unknown URI " + uri);
            }
        }
    }
    View Code
    7.)外部如何访问
            ContentResolver resolver = getContentResolver();
            Uri uri = Uri.parse("content://com.whoislcj.testsqlite.personprovider/person");
            //添加一条记录
            ContentValues values = new ContentValues();
            values.put("name", "whoislcj");
            resolver.insert(uri, values);
    
            //更新一条数据
            ContentValues updateValues = new ContentValues();
            updateValues.put("name", "lcj");
            //组合
            resolver.update(uri, updateValues, "id=?", new String[]{"2"});
            //单个
            Uri updateIdUri = ContentUris.withAppendedId(uri, 5);
            resolver.update(updateIdUri, updateValues, null, null);
            //删除person表指定数据
            Uri deleteIdUri = ContentUris.withAppendedId(uri, 5);
            resolver.delete(deleteIdUri, null, null);
    
            //获取person表指定数据
            Uri tempUri = ContentUris.withAppendedId(uri, 5);
            Cursor cursor = resolver.query(tempUri, null, null, null, "id asc");
            while (cursor.moveToNext()) {
                Log.e("testContentProvider", "signal id=" + cursor.getInt(0) + ",name=" + cursor.getString(1));
            }
            cursor.close();
    
            //获取person表中所有记录
            cursor = resolver.query(uri, null, null, null, "id asc");
            while (cursor.moveToNext()) {
                Log.e("testContentProvider", "id=" + cursor.getInt(0) + ",name=" + cursor.getString(1));
            }
            cursor.close();
    View Code
    8.)如何监听数据变化

    需要注册一个自定义的观察者,当时如下

         // 为uri的数据改变注册监听器
            getContentResolver().registerContentObserver(
                    Uri.parse("content://com.whoislcj.testsqlite.personprovider/person"), true,
                    new Observer(new Handler()));
    
        // 提供方自定义的ContentOberver监听器
        private final class Observer extends ContentObserver {
    
            public Observer(Handler handler) {
                super(handler);
            }
    
            @Override
            public void onChange(boolean selfChange, Uri uri) {
                // 查询发送邮箱中的短息(处于正在发送状态的短信放在发送箱)
                Log.e("MainActivity", "onChange--->uri :" + uri.toString());
            }
        }

    同样数据操作位置也需要执行如下代码

    getContext().getContentResolver().notifyChange(uri, null);
    9.)访问权限控制

    声明读写自定义权限

        <permission android:name="com.whoislcj.testsqlite.personprovider.read" />
        <permission android:name="com.whoislcj.testsqlite.personprovider.write" />
    
        <uses-permission android:name="com.whoislcj.testsqlite.personprovider.read" />
        <uses-permission android:name="com.whoislcj.testsqlite.personprovider.write" />

    ContentProvider注册声明:

           <provider
                android:name=".PersonProvider"
                android:authorities="com.whoislcj.testsqlite.personprovider"
                android:enabled="true"
                android:exported="true"
                android:readPermission="com.whoislcj.testsqlite.personprovider.read"
                android:writePermission="com.whoislcj.testsqlite.personprovider.write">
            </provider>

     10.)关于getTpye

            ContentProvider里面一个getType ()函数很多人不知道 这个干嘛的,接下来介绍一下,

        // 数据集的MIME类型字符串则应该以vnd.android.cursor.dir/开头
        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person";
        // 单一数据的MIME类型字符串应该以vnd.android.cursor.item/开头
        public static final String CONTENT_TYPE_ITME = "vnd.android.cursor.item/person";
    
        /**
         * 该方法用于返回当前Url所代表数据的MIME类型。
         *
         * @param uri
         * @return
         */
        @Override
        public String getType(Uri uri) {
            switch (uriMatcher.match(uri)) {
                case INCOMING_COLLECTION:
                    return CONTENT_TYPE;
                case INCOMING_SIGNAL:
                    return CONTENT_TYPE_ITME;
                default:
                    throw new IllegalArgumentException("Unknown URI " + uri);
            }
        }

    假设我们在项目搞了一个联系人列表Activity,我们需要外面来访问这个Activity,首先看下这个Activity的注册声明:

    <activity android:name=".TestActivity" android:icon="@mipmap/ic_launcher">
                <intent-filter>
                    <action android:name="com.whoislcj.testsqlite.personprovider" />
                    <category android:name="android.intent.category.DEFAULT"/>
                    <data android:mimeType="vnd.android.cursor.dir/person" />
                </intent-filter>
    
            </activity>

    看到上面的mimeType:vnd.android.cursor.dir/person

    外部如何启动呢:

        Uri uri = Uri.parse("content://com.whoislcj.testsqlite.personprovider/person");
                    Intent intent = new Intent();
                    intent.setAction("com.whoislcj.testsqlite.personprovider");
                    intent.setData(uri);
                    startActivity(intent);

    这样以来系统会去调用你定义的ContentProvider中的getType,去匹配出相应的Activity来实现跳转。

  • 相关阅读:
    EasyUI
    TortoiseSVN常用批处理命令 分类: C# 2014-08-09 11:31 647人阅读 评论(1) 收藏
    TortoiseSVN常用批处理命令 分类: C# 2014-08-09 11:31 648人阅读 评论(1) 收藏
    C# IIS应用程序池辅助类 分类: C# Helper 2014-07-19 09:50 248人阅读 评论(0) 收藏
    C# IIS应用程序池辅助类 分类: C# Helper 2014-07-19 09:50 249人阅读 评论(0) 收藏
    博客目录 分类: 其他 2014-07-16 22:58 370人阅读 评论(0) 收藏
    angular学习笔记(三十一)-$location(1)
    一些总是记不住又容易搞混淆的东西(不断更新)
    angular内置过滤器-filter
    angular-resource版本差异问题
  • 原文地址:https://www.cnblogs.com/whoislcj/p/5507928.html
Copyright © 2011-2022 走看看