最近在复习ContentProvider时遇到了一些问题,几经波折,终于解决了,故写下这篇博客,希望能帮到有相同问题的兄弟。
当我们想要一个应用的数据向外部公开时,ContentProvider是一个不错的选择
我把两个应用分别叫做client和service,client是我的需要请求其他数据的应用,service是提供数据的应用
需要生成ContentProvider的子类
public class MyProvider extends ContentProvider {public MyProvider() {}@Overridepublic 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");}@Overridepublic String getType(Uri uri) {// TODO: Implement this to handle requests for the MIME type of the data// at the given URI.throw new UnsupportedOperationException("Not yet implemented");}@Overridepublic Uri insert(Uri uri, ContentValues values) {// TODO: Implement this to handle requests to insert a new row.throw new UnsupportedOperationException("Not yet implemented");}@Overridepublic boolean onCreate() {// TODO: Implement this to initialize your content provider on startup.return false;}@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {// TODO: Implement this to handle query requests from clients.return getContext().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);}@Overridepublic 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");}
}
里面都是一些默认方法,只是重写了query这个查询方法。内容提供器属于四大组件之一,使用时要先声明
这里的重点是authorities属性,他表明外部应该通过com.example.myprivider.provider来访问我们的ContentProvider,格式默认是包名.provider,同时也要enabled启动ContentProvider和exported允许外部访问
由于query方法访问我们的手机通讯录,我们在使用时先添加权限
代码请求权限
requestPermission(this, Manifest.permission.READ_CONTACTS);public static void requestPermission(Activity activity, String permission) {if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(activity, new String[]{permission}, 1);}
}
这样我们的service应用就写好了。
这个代码比较简单
Uri uri = Uri.parse("content://com.example.myprivider.provider");
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {StringBuilder sb = new StringBuilder();do {@SuppressLint("Range") String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));@SuppressLint("Range") String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));sb.append(name).append(", ").append(number).append("\n");} while (cursor.moveToNext());binding.textView.setText(sb);
}
观察一下,uri比较重要,他是我们访问ContentProvider的重要角色,一般格式是content://访问的包名.provider/表名/序号。访问的包名.provider并不是绝对的,和我们的authorities属性(已加粗,往上找)有关,建议直接复制。其中表名和序号可有可无,具体看service中ContentProvider的实现,一般用来做一下标记,方便知道查询的是哪张表。
我们写完之后,还是不能直接访问,高版本的sdk要求我们必须提前声明要查询哪一个ContentProvider
这里的包名就是我们service的包名了
做完之后,先启动我们的service,申请访问权限,在启动client,就可以通过ContentProvider间接访问到通讯录了。
1.ContentProvider一般配合SQLiteOpenHelper组合使用,db的query方法也是生成Cursor类,可以直接被ContentProvider返回
2.service应用一定要先启动
3.剩下的看评论区问题,再补充
下一篇:滑动窗口最大值:单调队列