您当前所在位置:ag旗舰厅 > 热门新闻 >

Android基础到进阶四大组件之ContentProvider详解

Android挑供了5栽手段来让用户保存持久化行使程序数据。按照本身的需求来做选择,比如数据是否是行使程序私有的,是否能被其他程序访问,必要众幼批据存储空间等,别离是:

行使SharedPreferences存储数据文件存储数据SQLite数据库存储数据「行使ContentProvider存储数据」网络存储数据

咱们今天就来学习一下ContentProvider。行为Android四大巨头之一的他有点徒负谣言,由于在清淡的开发过程中,行使的次数比较少。大片面行使的数据缓存用SharedPreferences就能搞定了。

「ContentProvider(数据挑供者)是行使程序之间共享数据的一栽接口机制,是一栽更为高级的数据共享手段。」

ContentProvider能够指定必要共享的数据,而其他行使程序则能够在不清新数据来源、路径的情况下,对共享数据进走添删改查等操作。

在Android体系中,很众Android体系内置的数据也是议定ContentProvider挑供给用户行使,例如通讯录、音视频文件和图像文件等。

什么是ContentProviderContentProvider是Android的四大组件之一,以标准化的手段在Android 行使间共享数据。ContentProvider封装的数据存储以及添删改查等,并且必须实现一个对外联相符的接口(Uri)。什么是Uri

Uri(通用资源标识符 Universal Resource Identifer),代外数据操作的地址,每一个ContentProvider都会有唯一的地址。

ContentProvider行使的Uri语法组织如下:

content://authority/data_path/id
「content://」 是通用前缀,外示该Uri用于ContentProvider定位资源。「authority」 是授权者名称,用来确定详细由哪一个ContentProvider挑供资源。因此清淡authority都由类的幼写全称构成,以保证唯一性。「data_path」 是数据路径,用来确定乞求的是哪个数据集。「id」 是数据编号,用来乞求单条数据。倘若是众条这个字段无视。

样例:

content://com.scc.userprovider/user众条content://com.scc.userprovider/user/10单条
什么是ContentResolverContentResolver是数据调用者,ContentProvider将数据发布出来,议定ContentResolver对象结相符Uri进走调用。清淡来说ContentProvider是单例模式,众个行使可议定ContentResolver调用ContentProvider的添删改查操作数据,ContentResolver调用的数据操作会让联相符个ContentProvider处理。创建ContentProvider创建一个类让其继承ContentProvider,并重载6个函数

必要实现的主要手段是:

「insert()」、「delete()」、「update()」、「query()」:用于对数据集的添删改查操作。「onCreate()」:清淡用来初起化底层数据集和竖立数据连接等做事「getType()」:用来返回指定Uri的MIME数据类型,若Uri是单条数据,则返回的MIME数据类型以vnd.Android.cursor.item起头;若Uri是众条数据,则返回的MIME数据类型以vnd.android.cursor.dir/起头。

数据访问手段「如insert(Uri,ContentValues)和update(Uri,ContentValues,Bundle)」 能够同时从众个线程调用,并且必须是线程坦然的。其他手段「如onCreate()」 仅从行使程序主线程调用,并且必须避免实走冗长的操作。请参阅其预期线程走为的手段描述。

2. 声明Uri规则,实现UriMatcher

咱先来望望UriMatcher是干嘛的,UriMatcher内心上是一个文本过滤器,有助于解析Uri,用在ContentProvider中协助吾们过滤,分辨出查询者想要查询哪个数据外。

UriMatcher的组织函数中,UriMatcher.NO_MATCH是Uri无匹配时的返回代码,值为-1。addUri()手段用来增补新的匹配项,语法为:

public void addUri(String authority, String path, int code)
authority外示匹配的授权者名称;path外示数据路径;code外示返回代码。

下面咱搞个实例:

//这里的名称必须与AndroidManifest.xml中android:authorities保持相反public static final String AUTHORITY = "com.scc.userprovider";//数据路径public static final String PATH_USERS = "user";//访问ContentProvider的URLpublic static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + PATH_USERS);//返回代码public static final int USER_INFO = 1;//创建UriMatcher对象private static UriMatcher uriMatcher;//创建静态代码块static {      //实例化UriMatcher对象      uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);      //参数1:authority;参数2:路径;参数3:自定义代码      uriMatcher.addURI(UserInfoContent.AUTHORITY, UserInfoContent.PATH_USERS, USER_INFO);}

3.注册ContentProvider

在AndroidManifest.xml文件中的 application节点下行使标签注册。样例:

<!--android:name指定ContentProvider实现的类名android:authorities指定ContentProvider对答Uri(相等于ContentProvider分配一个域名)android:exported指定ContentProvider是否批准其他行使调用。倘若将该属性竖立为true,则批准其他行使调用--><android:authorities="com.scc.userprovider"    android:name=".UserProvider"    android:exported="true"/>
行使ContentProvider议定insert()手段增补单条数据
ContentValues cv = new ContentValues();cv.put(UserInfoContent._ID, bean.get_id());cv.put(UserInfoContent.USER_NAME, bean.getName());cv.put(UserInfoContent.USER_AGE, bean.getAge());cv.put(UserInfoContent.USER_UPDATE_TIME, bean.getUpdate_time());Uri uri = getContentResolver().insert(UserInfoContent.CONTENT_URI, cv);Log.e(getClass().getName(), "insert:" + uri);
议定bulkInsert()手段增补众条数据
ContentValues[] arrayValues = new ContentValues[10];//实例化每一个ContentValues...int count = getContentResolver().bulkInsert(UserInfoContent.CONTENT_URI, arrayValues);

2.指定ID删除单条数据

int delete = getContentResolver().delete(UserInfoContent.CONTENT_URI, "_id=12", null);Log.e(getClass().getName(), "delete(战败返回-1):" + delete);
议定selection语句删除众条数据
String selection = UserInfoContent._ID + ">12";int result = getContentResolver().delete(UserInfoContent.CONTENT_URI, selection, null);

3.修改数据

UserInfoBean bean = new UserInfoBean("蚩尤", 32, "12:00");ContentValues cv = new ContentValues();cv.put(UserInfoContent.USER_NAME, bean.getName());cv.put(UserInfoContent.USER_AGE, bean.getAge());cv.put(UserInfoContent.USER_UPDATE_TIME, bean.getUpdate_time());getContentResolver().update(UserInfoContent.CONTENT_URI, cv, "_id=18", null);

4.查询数据

Cursor cursor = getContentResolver().query(UserInfoContent.CONTENT_URI, null, selection, null, null);//循环掏出游标指向的每条用户记录while (cursor.moveToNext()) {    UserInfoBean user = new UserInfoBean();    user.name = cursor.getString(cursor.getColumnIndex(UserInfoContent.USER_NAME));    user.age = cursor.getInt(cursor.getColumnIndex(UserInfoContent.USER_AGE));    user._id = cursor.getString(cursor.getColumnIndex(UserInfoContent._ID));    user.update_time = cursor.getString(cursor.getColumnIndex(UserInfoContent.USER_UPDATE_TIME));    userList.add(user); //增补到用户新闻列外}cursor.close(); //关闭数据库游标Log.e(getClass().getName(), "Query用户:" + String.format("现在共找到%d个用户", userList.size()));
跨行使行使ContentProvider

跨行使和本行使行使ContentProvider相通的手段,这儿就不做复制了。

例5的Uri是拼接字段,但是拼接后的效果 「content://com.scc.userprovider/user。」

跨平台行使getContentResolver().手段 的第一个参数:

「Uri uricontent = Uri.parse("content://com.scc.userprovider/user");」

ContentValues cv = new ContentValues();cv.put(UserInfoContent._ID, bean.get_id());cv.put(UserInfoContent.USER_NAME, bean.getName());cv.put(UserInfoContent.USER_AGE, bean.getAge());cv.put(UserInfoContent.USER_UPDATE_TIME, bean.getUpdate_time());Uri uri = getContentResolver().insert(uricontent, cv);Log.e(getClass().getName(), "insert:" + uri);

1.新添数据+查找数据

2.修改数据+删除数据

「java.lang.SecurityException: Permission Denial: opening provider com.scc.cp.UserProvider from ProcessRecord」

解决方案:

在AndroidManifest.xml文件中的 application节点下行使标签注册时android:exported="false"时,不批准其他行使调用。因而其他和行使行使ContentProvider会歇业报错。将exported改为:android:exported="true"即可。

末了

幼编学习升迁时,顺带从网上搜集清理了一些 Android 开发有关的学习文档、面试题、Android 中央笔记等等文档,期待能协助到行家学习升迁,如有必要参考的能够直接往吾 GitHub地址:https://github.com/733gh/Android-T3 访问查阅。

GitHub地址:github.com