2019年开始了,2018年对于Android学习太杂,懂得了很多框架的使用但又很容易忘记。鉴于此,我决定系统学习Android知识,从入门路线开始,并坚持写总结,记录我的Android学习之路。
内容提供器是Android跨程序数据交流的工具,提供了一套完整的机制。允许一个程序访问另外一个程序的数据,同时还能保证被访问数据的安全性,可选择部分数据进行共享。本篇介绍其基本用法以及相关事项。
- 运行时权限申请
- 读取其他程序的数据
- 发送数据给其他程序
运行时权限申请
在Android 7.0以上,权限被分为普通权限和危险权限,危险权限需要动态申请。申请步骤如下:
- 利用ContextCompat的checkSelfPermission()方法检查是否已经取得权限
- 未取得权限,利用ActivityCompat的requestPerssion()方法申请权限
- 重写onRequestPermissionResult()方法,对申请结果进行处理。
public class ContentResolverTestActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content_resolver_test);
//第一步
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED){
//第二步, 第三个参数传送唯一值即可
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_CONTACTS},
1);
} else {
//取得权限后的业务逻辑
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//第三步
switch (requestCode){
case 1 :
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
//处理取得权限和后的业务逻辑
} else {
//未取得权限的业务逻辑
Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
}
break;
default :
}
}
}
读取其他程序的数据
- 动态申请相关权限
- 利用Context的getContentResolver()方法获取ContentResovler
- 执行ContentResovler的query方法得到一个Cursor对象
- 对获得的Cursor进行处理
//第一步在上面申请了
private void readContact(){
Cursor cursor = null;
//第二、第三步
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, null, null, null);
//第四步
if (cursor != null){
while (cursor.moveToNext()){
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds
.Phone.NUMBER));
contactList.add(name + "\n" + number);
}
}
adapter.notifyDataSetChanged();
cursor.close();
}
query方法可传入五个参数,具体用法与SQLiteDatabase类似。
参数 | 对应sql语句 |
---|---|
uri | from table |
projection | select column1 |
selection | where column1 = value |
selectionArgs | where column1 = ? |
sortOrder | order by column1 |
uri值内容URI,是数据表的唯一标识符,由authority和path组成,如下:
content://com.example.app.provider/table1
获取Uri对象可利用Uri.parse(string)
方法。
获取完结果之外记得把cursor关掉
发送数据给其他程序
- 用Android Studio创建ContentProvider类(默认在AndroidManifest.xml帮我们注册好了)
- 声明表对应项目的代码和UriMatcher,用于确认用户正在对哪一个表进行什么操作。
- 实现CRUD具体逻辑
- 实现getType()返回uri对应MIME类型
public class MyContentProvider extends ContentProvider {
//第二步
public static final int TABLE1_DIR = 0;
public static final int TABLE1_ITEM = 1;
private static final String AUTHORITY = "com.example.learnapplication";
private static UriMatcher uriMatcher;
//第二步,在静态代码块中给UriMatcher添加URI
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "table1", TABLE1_DIR);
uriMatcher.addURI(AUTHORITY, "table1/#", TABLE1_ITEM); // line A
}
public MyContentProvider() {
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// Implement this to handle requests to delete one or more rows.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public String getType(Uri uri) {
//第四步,返回对应MIME类型。 line B
switch (uriMatcher.match(uri)){
case TABLE1_DIR:
return "vnd.android.cursor.dir/vnd.com.example.learnapplication.table1";
case TABLE1_ITEM:
return "vnd.android.cursor.item/vnd.com.example.learnapplication.table1";
default:
return null;
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO: Implement this to handle requests to insert a new row.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public boolean onCreate() {
// TODO: Implement this to initialize your content provider on startup.
return false;
}
@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;
default:
}
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO: Implement this to handle requests to update one or more rows.
throw new UnsupportedOperationException("Not yet implemented");
}
}
authority是在新建ContentProvider的时候确定的,必须为唯一值,通常采用包名代替。
line A 在UriMatcher添加通配符,以匹配任意数字或字符。比如可匹配content://com.example.learnapplication/table1/1
,最后的1通常代表表中id为1的数据。
-
*
:表示匹配任意长度的任意字符。 -
#
:表示匹配任意长度的数字。
line B 用于获取Uri对应的MIME类型,一个内容URI对应的MIME通常由三部分组成: - 必须以vnd开头
- 如果内容URI以路径为结尾,后接
android.cursor.dir/
;如果内容URI以id结尾,后接android.cursor.item/
。 - 最后接上
vnd.
.
参考资料
《第一行代码》