前言:
上一篇介绍广播接收者(BroadcastReceover),本篇继续,记叙下Android四大组件最后一个不常用,但是非常有用的ContentProvider。Google文档
本文主要从以下几个方面介绍:
特点优缺点数据访问创建内容提供器工作机制
特点
Android四大组件之一,需要进行注册,一般有name,authorities,export等属性是一种定义数据共享的接口,并是不android数据存储的方式之一跨进程数据访问android系统很多系统应用都是使用ContentProvider方式进行储存的(图片,通讯录,视频,音频等)数据更新监听方便
优缺点
优点:
为数据访问提供统一的接口,解决了不同储存方式需要不同的API的访问所带来的繁琐跨进程数据的访问,实现了不同App数据访问提供了很大的便利
缺点:
不能单独使用,必须需要和其他的储存方式结合使用
数据访问
下面示例如何获取通讯录信息: Activity:
public class ContentProviderActivity extends AppCompatActivity {
private ContentResolver mContentResolver;
StringBuilder builder=
new StringBuilder(
"");
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content_provider);
mContentResolver=getContentResolver();
tv= (TextView) findViewById(R.id.tv_show_contract);
findViewById(R.id.tv_press_contract).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
if(ContextCompat.checkSelfPermission(ContentProviderActivity.
this, android.Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(ContentProviderActivity.
this,
new String[]{Manifest.permission.READ_CONTACTS},
1);
}
else{
readContacts();
}
}
});
}
private void readContacts(){
Cursor cursor=
null;
try {
cursor=mContentResolver.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));
builder.append(displayName);
builder.append(
": ");
builder.append(number);
builder.append(
" ");
Log.i(
"wy",displayName+
" "+number);
}
}
}
catch (Exception e){
e.printStackTrace();
}
finally {
if(cursor!=
null){
cursor.close();
}
tv.setText(builder);
}
}
}
以上:
借助ContentResolver类访问内容提供器中共享的数据,其提供了一系列的增删改查(CRUD)操作,其中insert方法用于添加数据,update更新数据,delete删除数据,query用于查询数据。和SQLiteDatabase类似,只是参数上稍微有些区别,ContentResolver中接收的参数是不接收表名参数的,而是使用一个Uri参数代码(关于Uri内容欢迎参考一篇就够了系列之Activity全解析中关于Scheme的介绍)。由于联系人信息是危险权限,所以需要动态申请,同时manifest中也需要申明代码中的查询等方法可以看到是个常量,其实也源码的一个封装。
创建内容提供器
public class MyContentProvider extends ContentProvider {
public static final int DIR1=
0;
public static final int ITEM1=
1;
public static final int DIR2=
2;
public static final int ITEM2=
3;
public static final String AUTHRITY=
"com.wenyi.interview.provider";
private static UriMatcher uriMatcher;
private MyDatabaseHelper dbhelper;
static {
uriMatcher=
new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHRITY,
"book",DIR1);
uriMatcher.addURI(AUTHRITY,
"book/#",ITEM1);
uriMatcher.addURI(AUTHRITY,
"category",DIR2);
uriMatcher.addURI(AUTHRITY,
"category/#",ITEM2);
}
/**
* 初始化内容提供器的时候调用,通常会在这里完成对数据库的创建和升级等操作
* @return true表示初始化成功,false表示初始化失败
* 只有当contentResolver尝试访问我们的程序中的数据是,内容提供器才会被初始化
*/
@Override
public boolean onCreate() {
dbhelper=
new MyDatabaseHelper(getContext(),
"MyStore.db",
null,
2);
return true;
}
/**
* 查询数据
* @param uri 确定查询哪张表
* @param projection 确定查询哪些列
* @param selection 约束查询哪些行
* @param selectionArgs 约束查询哪些行
* @param sortOrder 用于对结果进行排序,查询的结果存放在Cursor对象中返回
* @return
*/
@Nullable
@Override
public Cursor
query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
SQLiteDatabase db=dbhelper.getReadableDatabase();
Cursor cursor=
null;
switch (uriMatcher.match(uri)){
case DIR1:
cursor=db.query(
"Book",projection,selection,selectionArgs,
null,
null,sortOrder);
break;
case ITEM1:
String bookid=uri.getPathSegments().get(
1);
cursor=db.query(
"Book",projection,
"id=?",
new String[]{bookid},
null,
null,sortOrder);
break;
case DIR2:
cursor=db.query(
"Category",projection,selection,selectionArgs,
null,
null,sortOrder);
break;
case ITEM2:
String categoryid=uri.getPathSegments().get(
1);
cursor=db.query(
"Category",projection,
"id=?",
new String[]{categoryid},
null,
null,sortOrder);
break;
default:
break;
}
return cursor;
}
/**
*
* @param uri
* @return 传入的内容URI来返回相应的MIME类型
*/
@Nullable
@Override
public String
getType(@NonNull Uri uri) {
switch (uriMatcher.match(uri)){
case DIR1:
return "vnd.android.cursor.dir/vnd.com.wenyi.interview.provider.book";
case ITEM1:
return "vnd.android.cursor.item/vnd.com.wenyi.interview.provider.book";
case DIR2:
return "vnd.android.cursor.dir/vnd.com.wenyi.interview.provider.category";
case ITEM2:
return "vnd.android.cursor.item/vnd.com.wenyi.interview.provider.category";
default:
break;
}
return null;
}
/**
* 添加数据
* @param uri 确定要添加到的表
* @param values 待添加的数据
* @return 添加完成后,返回一个用于表示这条心记录的URI
*/
@Nullable
@Override
public Uri
insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
/**
* 删除数据
* @param uri 确定删除哪一张表中的数据
* @param selection 约束删除哪些行
* @param selectionArgs 约束删除哪些行
* @return 被删除的行
*/
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
/**
* 更新数据
* @param uri 更新的表
* @param values 新数据保存在其中
* @param selection 约束更新的行
* @param selectionArgs 约束更新的行
* @return 受影响的行作为返回值
*/
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
}
代码有点长,现在来细细分析:
自定义MyContentProvider继承自ContentProvider,重写相应的方法,方法都有解释四个常量分别表示访问Book表中的说有数据,访问Book表中的单条数据,访问Category表中的所有数据和访问Category表中的单条数据在manifest中进行注册,<provider android:exported="true" android:enabled="true" android:authorities="com.wenyi.interview.provider" android:name=".FourComponet.contentProvider.MyContentProvider"/>代码中,UriMatche类,可以用来配皮Uri类型数据,其中,“*”和“#”分别表示匹配任意长度的任意字符和任意长度的数字。创建MyDatabaseHelper对象,继承自SQLiteOpenHelper,方便数据可操作,因为内容提供着只是接口标准,需要和数据存储方式结合使用只在query中写了相应代码,其他方法也需要写类似代码getType方法中,返回值很奇特。实际上,这是MIME字符格式,MIME主要由3部分组成,在Android中,格式为: a: 必须以vnd开头 b: 如果内容Uri以路径结尾,则后面接 android.cursor.dir/。如果内容Uri以id结尾,则后面接android.cursor.item/ c: 在最后面接 vnd.authority.path 这样,我们的内容提供器就创建完成了,通过这种机制,必须知道URI,才能顺利的访问该数据库中的内容,比保证了可访问,又保证了安全性。
工作机制
暂不分析
欢迎阅读其他系列文章:
一篇就够了系列之Activity全解析
一篇就够了系列之Service全解析
一篇就够了系列之BroadcastReceiver全解析