在Android应用开发中我们常常需要和其他应用进行交互,之前对这些问题没有仔细了解过,现在来做一下总结。
Android应用之间数据的交互方式:
- 获取系统应用的数据
- 提供数据给其他应用
- 应用之间的分享
下面介绍获取系统应用的数据
实例分析
以获取联系人数据为例,代码如下:
1 | Cursor cursor=getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null); |
ContentResolver类的query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder)方法参数的介绍:uri用来指明要访问的数据的位置projection访问的列,如果为null,则表示访问所有列selection用于指定查询条件selectionArgs查询参数sortOrder排序顺序
基本流程
那么ContentResolver是怎么通过query方法来获取联系人的数据的呢?下面我们来分析ContentResolver的源码:
1 | //1 |
在ContentResolver的源码中query有三个重载方法1,2,3,在实例中我们调用重载方法1,方法1中则直接调用方法2。在方法2中,封装了数据到Bundle中,并调用了方法3,真正的实现在方法3中。方法3中的核心方法是acquireUnstableProvider(Uri uri),它获取IContentProvider(一个IPC 接口),并通过IContentProvider来获取联系人的数据。而acquireUnstableProvider(Uri uri)调用的是acquireUnstableProvider(Context c, String name)方法,它是个抽象方法,具体的实现类是ApplicationContentResolver。
ApplicationContentResolver的acquireUnstableProvider方法源码如下:
1 |
|
在ApplicationContentResolver的acquireUnstableProvider方法调用了ActivityThread的acquireProvider方法,源码如下:
1 | public final IContentProvider acquireProvider( |
ApplicationContentResolver通过调用ActivityThread的acquireProvider方法来获取ContentProvider;ActivityThread先会判断缓存中是否存在要求的IContentProvider,
如果存在就直接返回,如果不存在就调用AMS的getContentProviderImpl()和installProvider来获取。
关于AMS获取IContentProvider的详细流程,可以看ContentProvider启动过程分析
ContactsContract详解
ContactsContract是存储联系人的数据表的常量字段,它有几个常用的内部类如下:
- ContactsContract.Data:数据表的常量,包含与原始联系人关联的数据点。 数据表的每一行通常用于存储单条联系信息(例如电话号码)及其相关元数据(例如,它是工作号码还是家庭号码)
- ContactsContract.CommonDataKinds:用于定义存储在ContactsContract.Data表中的公共数据类型的容器。
- ContactsContract.Contacts:联系人表的常量,包含代表同一个人的每个原始联系人聚合的记录
联系人数据是存储在数据库中(具体位置在data/data/com.android.providers.contacts/databases中),根据其MIME类型来判断其位置所代表的意义。如
ContactsContract.CommonDataKinds.Phone.NUMBER和ContactsContract.CommonDataKinds.Email.ADDRESS都表示data1,但是在数据库中不同的MIME类型的data1表示不同的数据。
数据库中data表的字段和数据如下(字段太多,只截取了部分)

MIME类型如下

通过MIME类型来获取所需要的数据
1 | Uri p = ContactsContract.Data.CONTENT_URI; |
ContentResolver()还有insert、delete、update方法,其用法与query类似,这里不再介绍。
获取其他系统应用数据
CalendarContract
CalendarContract是存储日历和事件相关信息字段表,与ContactsContract类似。CalendarContract也有几个内部类,常用的是CalendarContract.Events,包含诸如事件标题,位置,开始时间,结束时间等信息。CalendarContract.Events的使用如下:1
2
3
4
5
6
7
8
9
10
11 Uri p = CalendarContract.Events.CONTENT_URI;
Cursor cursor=getActivity().getContentResolver().query(p, null,null, null, null);
while (cursor.moveToNext()){
StringBuilder builder = new StringBuilder();
builder.append("标题 : "+cursor.getString(cursor.getColumnIndex(CalendarContract.Events.TITLE))+"\n")
.append("起始时间 :"+cursor.getString(cursor.getColumnIndex(CalendarContract.Events.DTSTART))+"\n")
.append("结束时间 :"+cursor.getString(cursor.getColumnIndex(CalendarContract.Events.DTEND))+"\n")
.append("描述 : "+cursor.getString(cursor.getColumnIndex(CalendarContract.Events.DESCRIPTION))+"\n");
contents.add(builder.toString());
}
cursor.close();
更多关于CalendarContract的使用,可以查看官方文档。
MediaStore
MediaStore包含内部和外部存储设备上所有可用媒体的元数据。其内部类如下:
- MediaStore.Audio:集装箱所有的音频内容。
- MediaStore.Files:媒体提供程序表,包含媒体存储中所有文件的索引,包括非媒体文件。
- MediaStore.Images:包含所有可用图像的元数据
- interface MediaStore.MediaColumns:大多数MediaProvider表的公共字段
- MediaStore.Video:包含所有可用视频的元数据
1 | List<String> contents = new ArrayList<>(); |
Settings
Settings与XXXContract不同,它是通过xml文件来存储数据,在文件/data/system/users/0/目录下,获取设置的方式如下:1
2
3
4
5
6
7
8
9
10StringBuilder builder = new StringBuilder();
ContentResolver contentResolver=getActivity().getContentResolver();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
builder.append("wifi是否开启:"+Settings.Global.getString(contentResolver,Settings.Global.WIFI_ON)+"\n")
.append("数据流量是否开启:"+Settings.Global.getString(contentResolver,Settings.Global.DATA_ROAMING)+"\n")
.append(Settings.System.NOTIFICATION_SOUND+" "+Settings.System.getString(contentResolver,Settings.System.NOTIFICATION_SOUND)).append("\n")
.append(Settings.System.SCREEN_BRIGHTNESS+" "+Settings.System.getString(contentResolver,Settings.System.SCREEN_BRIGHTNESS)).append("\n")
.append(Settings.System.TEXT_SHOW_PASSWORD+" "+Settings.System.getString(contentResolver,Settings.System.TEXT_SHOW_PASSWORD)).append("\n");
}
Log.d("==============",builder.toString());
更多关于Setting的内容可以看Android系统APP之SettingsProvider
注意:以上的操作都是需要申请权限的
异步处理
如果请求数据的操作太过耗时,可能造成ANR,因此需要异步处理。异步处理的方式有:
- Thread + Handler
- AsyncTask
- Loader
- RxJava
参考文章: