在Android平台上,应用程序之间是相对独立的,分别运行在自己的进程中,如果应用程序之间相互共享数据是需要借助ContentResolver类。ContentResolver用于保存和检索数据,应用程序之间可以提供数据的访问操作,ContentResolver是实现程序数据共享的重要途径。
ContentResolver(内容提供器)主要有两个用法:一.使用现有的内容提供器来读取和操作相应程序中的数据,二.创建自己内容提供器的对外接口(就是通过这个接口来实现外部应用程序共享数据的)。
在使用ContentResolver之前,需要脑补一下运行时权限,什么是运行时权限,简单的说就是自我保护(应用程序保护用户的隐私信息);记得QQ空间有个设置,并非好友不可访问QQ空间对吧!这是权限,比如,你注册APP成为用户的时候,它是不是有提醒说:你是需要注册一个APP账号还是用手机号码快速注册,如果你是用手机号码注册的,它会给你发一条验证码短信,那请问你希望它给你短信吗?这个权限要开放吗?好,注册好之后,是不是需要完备自己的资料,头像设置一个吧!图片是不是从图库里来选呀!那问题来了,图库这个应用希望别的应用软件来访问它且共享它的资源吗(一般这个权限都是开放的)?在Android6.0之后,权限有了新的变化;当你注册好进入软件应用里面,它会提示你本应用需要访问你的电话薄,拒绝还是同意?本应用需要访问你的媒体库,拒绝还是同意?脑补到这吧!
使用ContentResolver不复杂,因为,前面学过SQL语句、学过SQLite数据库,ContentResolver和他们的用法一样,ContentResolver同样也提供了对数据的增删改查操作,只是参数不同而已。参数用Uri来代替,称为内容URI,内容URI给内容提供器中的数据建立了唯一标识符,主要由三部分组成:content://包名/表名(数据路径),提示:URI字符串开头必须加上协议声明content://。URI不能直接使用,需要将它解析成Uri对象才可以作为参数传入,调用Uri.parse()方法即可。例:Uri uri= Uri.parse("content://包名/表名(数据路径)")。
使用ContentResolver要通过Context中的getContentResolver方法获得该类的实例。常用方法如下:
查询:query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder),
uri:指定查询某个应用程序下的某一张表,
projection:指定查询的列名,
selection:指定where的约束条件,
selectionArgs:为where中的占位符提供具体的值,
sortOrder:指定查询结果的排序方式。
插入:insert(Uri uri,ContentValues values)
更新:update(Uri uri,ContentValues values,String selection,String[] selectionArgs)
删除:delete(Uri uri,String selection,String[] selectionArgs)
getType(Uri uri):获取MIME数据类型, onCreate():创建ContentResolver时调用
ContentResolver用法一:查询系统ContentResolver(查询手机联系人例子)
package com.xhm.demo.myandroidsql;
import android.Manifest;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.provider.ContactsContract;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class ContentResolverActivity extends AppCompatActivity {
ArrayAdapter<String> adapter;
List<String> contactsList=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content_resolver);
ListView contactsView=(ListView) findViewById(R.id.contacts_view);
adapter=new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,contactsList);
contactsView.setAdapter(adapter);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_CONTACTS)!=
PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this,new String[]{
Manifest.permission.READ_CONTACTS},1);
}else {
readContacts();
}
}
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 displayName=cursor.getString(cursor.getColumnIndex
(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
//获取联系人手机号码
String number=cursor.getString(cursor.getColumnIndex
(ContactsContract.CommonDataKinds.Phone.NUMBER));
//添加数据
contactsList.add(displayName+"\n"+number);
}
adapter.notifyDataSetChanged();
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (cursor!=null){
cursor.close();//关闭数据连接
}
}
}
@Override
public void onRequestPermissionsResult(
int requestCode,String[] permissions,int[] grantResults) {
switch (requestCode){
case 1:
if (grantResults.length>0&&grantResults[0]==
PackageManager.PERMISSION_GRANTED){
readContacts();
}else {
Toast.makeText(ContentResolverActivity.this,
"You denied the permission", Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
}
布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/contacts_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
记得申请权限:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
效果图
ContentResolver用法二:创建一个ContentResolver
这里还需要再深入的了解URL:
内容URL的格式主要有两种,1.以路径结尾的表示访问该表中的所有路径,2.以ID结尾的表示访问表中拥有相应ID的数据。
- URI代表要操作的数据,由scheme、authorites、path三部分组成
- eg:
- content://com.jxn.provider/person
- scheme | authorites | path
- 1,schema:表明要访问ContentProvider。固定为:"content://"
- 2,Authority(主机名或授权):定义了是哪个ContentProvider提供这些数据(一般都用当前包名)。
- 3,path:路径,可根据业务逻辑自定义。eg: person、person/insert、person/insert/10等等
- 4,ID:通常定义URI时使用"#"号占位符代替, 使用时替换成对应的数字
- "content://com.jxn.provider/ table/# 匹配表中任意一行数据内容的URI格式(#代表任意长度的数字)
- "content://com.jxn.provider/* 匹配任意表的内容RUI格式(*表示匹配任意长度的任意字符 )
Android系统提供了两个用于操作Uri的工具类:UriMatcher 和 ContentUris
- 1,UriMatcher类用于匹配Uri,用法如下:
- 第一步:把你需要匹配的Uri路径全部给注册上,如下:
- //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
- UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
- //如果match()方法匹配content://com.jxn.provider.personprovider/person路径,返回匹配码为1
- matcher.addURI("com.jxn.provider.personprovider", "person", 1);//添加需要匹配uri,如果匹配就会返回匹配码
- //如果match()方法匹配content://com.jxn.provider.personprovider/person/230路径,返回匹配码为2
- matcher.addURI("com.jxn.provider.personprovider", "person/#", 2);//#号为通配符
- 第二步:使用matcher.match(uri)方法对输入的Uri进行匹配,如果匹配成功就返回匹配码
- switch (matcher.match(Uri.parse("content://com.jxn.provider.personprovider/person/10"))) {
- case 1
- // 相应的业务操作
- break;
- case 2
- // 相应的业务操作
- break;
- default:
- // 相应的业务操作
- break;
- }
- 2,ContentUris类用于为路径加上ID和获取路径的ID
-
- 给Uri加上id: ContentUris.withAppendedId(uri, id)
- 获取id: ContentUris.parseId(uri)
注意getType()方法,它是所有的内容提供器都必须提供的一个方法,用于获取Uri对应的MIME数据类型,一个内容RUI所对应的MIME字符串主要由三部分组成:1.必须以vnb开头,2.如果内容RUI以路径结尾,则后接android.cursor.dir/,如果内容RUI以ID结尾,则后接android.cursor.item/,3.后部接上vnb.<authority>.<path>。
package com.xhm.demo.myandroidsql;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.Nullable;
/**
* Created by Dell on 2017/3/31.
* 一个完整的ContentProvider
*/
public class MyContentResolver extends ContentProvider {
public static final int TABLE1_DIR=0;
public static final int TABLE1_ITEM=1;
public static final int TABLE2_DIR=2;
public static final int TABLE2_ITEM=3;
private static UriMatcher uriMatcher;
static {
uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("com.example.app.provider","table1",TABLE1_DIR);
uriMatcher.addURI("com.example.app.provider","table1/#",TABLE1_ITEM);
uriMatcher.addURI("com.example.app.provider","table2",TABLE2_DIR);
uriMatcher.addURI("com.example.app.provider","table2/#",TABLE2_ITEM);
}
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
switch (uriMatcher.match(uri)){
case TABLE1_DIR:
//查询table1表中的所有数据
break;
case TABLE1_ITEM:
//查询table1表中的单条数据
break;
case TABLE2_DIR:
//查询table2表中的所有数据
break;
case TABLE2_ITEM:
//查询table2表中的单条数据
break;
default:
break;
}
return null;
}
@Nullable
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)){
case TABLE1_DIR:
return "vnd.android.cursor.dir/vnb.com.example.app.provider.table1";
case TABLE1_ITEM:
return "vnd.android.cursor.item/vnb.com.example.app.provider.table1";
case TABLE2_DIR:
return "vnd.android.cursor.dir/vnb.com.example.app.provider.table2";
case TABLE2_ITEM:
return "vnd.android.cursor.item/vnb.com.example.app.provider.table2";
default:
break;
}
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
return 0;
}
}