内容提供器(Content Provider)用于在不同的应用程序之间实现数据共享的功能,同时还能保证被访数据的安全性。目前,使用内容提供器是Android实现跨程序共享数据的标准方式。

运行时权限

安卓将权限分成普通权限和危险权限。区别在是否威胁到用户的安全和隐私。

涉及到普通权限的操作系统会自动授权,涉及到危险权限的操作需要向安卓系统申请权限许可。
在安卓6.0之前,涉及到危险的权限,直接在androidmanifest.xml里面写userpermission就可以实现。但是在更高版本的安卓中不可以。

高版本安卓需要申请运行时权限。

  1. public void onCreate(){
  2. if (ContextCompat.checkSelfPermission(this,
  3. Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED) {
  4. ActivityCompat.requestPermissions(this, new String[]{
  5. Manifest.permission.READ_CONTACTS}, 1);
  6. }
  7. else {
  8. readContacts();
  9. }
  10. }
  11. //内容读取:读取联系人的信息
  12. private void readContacts() {
  13. Cursor cursor = null;
  14. try {
  15. //查询联系人数据:
  16. cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
  17. if (cursor != null){
  18. while (cursor.moveToNext()) {
  19. //获取联系人姓名:
  20. String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
  21. //获取联系人手机号
  22. String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
  23. contactsList.add(displayName + "\n" + number);
  24. }
  25. adapter.notifyDataSetChanged();
  26. }
  27. }catch (Exception e){
  28. e.printStackTrace();
  29. }
  30. finally {
  31. if (cursor != null){
  32. cursor.close();
  33. }
  34. }
  35. }
  36. @Override
  37. public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
  38. switch (requestCode){
  39. case 1:
  40. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  41. readContacts();
  42. }
  43. else {
  44. Toast.makeText(this, "you denied the permission", Toast.LENGTH_SHORT).show();
  45. }
  46. break;
  47. default:
  48. }
  49. }

第一步就是要先判断用户是不是已经给过我们授权了,借助的是ContextCompat.checkSelfPermission()方法。ContextCompat.checkSelfPermission()接受2个参数,第一个参数是context,然后是想要查询的权限。
调用ActivityCompat. requestPermissions()方法来向用户申请授权。

requestPermissions()方法接收3个参数,第一个参数要求是Activity的实例,第二个参数是一个String数组,我们把要申请的权限名放在数组中即可,第三个参数是请求码,只要是唯一值就可以了,这里传入了1。调用完了requestPermissions()方法之后,系统会弹出一个权限申请的对话框,然后用户可以选择同意或拒绝我们的权限申请,不论是哪种结果,最终都会回调到onRequest-PermissionsResult()方法中,而授权的结果则会封装在grantResults参数当中。这里我们只需要判断一下最后的授权结果,如果用户同意的话就调用call()方法来拨打电话,如果用户拒绝的话我们只能放弃操作,并且弹出一条失败提示。

  1. private boolean isStoragePermissionGranted() {
  2. if (Build.VERSION.SDK_INT >= 23) {
  3. final Context context = getApplicationContext();
  4. int readPermissionCheck = ContextCompat.checkSelfPermission(context,
  5. Manifest.permission.READ_EXTERNAL_STORAGE);
  6. int writePermissionCheck = ContextCompat.checkSelfPermission(context,
  7. Manifest.permission.WRITE_EXTERNAL_STORAGE);
  8. if (readPermissionCheck == PackageManager.PERMISSION_GRANTED
  9. && writePermissionCheck == PackageManager.PERMISSION_GRANTED) {
  10. Log.v("juno", "Permission is granted");
  11. return true;
  12. } else {
  13. Log.v("juno", "Permission is revoked");
  14. ActivityCompat.requestPermissions(this, new String[]{
  15. Manifest.permission.READ_EXTERNAL_STORAGE,
  16. Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
  17. return false;
  18. }
  19. } else { //permission is automatically granted on sdk<23 upon installation
  20. Log.v(TAG, "Permission is granted");
  21. return true;
  22. }
  23. }
  24. @Override
  25. public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
  26. super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  27. Log.v("juno", "onRequestPermissionsResult requestCode : " + requestCode
  28. + " Permission: " + permissions[0] + " was " + grantResults[0]
  29. + " Permission: " + permissions[1] + " was " + grantResults[1]
  30. );

访问其他程序的数据

使用现有的Content provider

使用简介

要获取设备上的文件,比如多媒体。可以通过2种方式。一种是遍历磁盘目录上的所有文件,通过后缀名找到。一种是通过安卓系统提供的 Media Provider 提出查询请求。当然最简单的方式是使用 Media Provider .

Content Provider可以为其他程序提供内容。私有的:只能为所在应用程序提供数据访问请求. exported = "false" 。公用的:为所有程序提供数据访问请求。exported = "true"。使用前注意在AndroidManifest.xml文件中注册。

借助context.getContentResolver()方法获取到ContentResolver实例,定义有insert(), update(), delete(), query()方法。

增删改查方法都是不接收表名参数的,而是使用一个Uri参数代替,这个参数被称为内容URI。内容URI给内容提供器中的数据建立了唯一标识符,它主要由两部分组成:authority和path。authority是用于对不同的应用程序做区分的,一般为了避免冲突,都会采用程序包名的方式来进行命名。比如某个程序的包名是com.example. app,那么该程序对应的authority就可以命名为com.example.app. provider。path则是用于对同一应用程序中不同的表做区分的,通常都会添加到authority的后面。比如某个程序的数据库里存在两张表:table1和table2,这时就可以将path分别命名为/table1和/table2,然后把authority和path进行组合,内容URI就变成了com.example.app.provider/table1和com.example.app.provider/table2。不过,目前还很难辨认出这两个字符串就是两个内容URI,我们还需要在字符串的头部加上协议声明。因此,内容URI最标准的格式写法如下:
image.png
传入了URL字符串,需要解析成URI对象,uri
image.png
image.png
ContentProvider还有notifyChange()方法,提醒数据变动。

https://blog.csdn.net/hb8676086/article/details/50164947

Cursor简介

Cursor是游标,储存数据,是行的集合。
在你理解和使用 Android Cursor 的时候你必须先知道关于 Cursor 的几件事情:

  • Cursor 是每行的集合。
  • 使用 moveToFirst() 定位第一行。
  • 你必须知道每一列的名称。
  • 你必须知道每一列的数据类型。
  • Cursor 是一个随机的数据源。
  • 所有的数据都是通过下标取得。

从cursor对象中取出数据:
image.png
向table1中添加数据:先添加数据到values里面,然后通过insert()方法,传入uri(之前已经绑定为table1)和values
image.png

项目实现:读取联系人信息

  1. //实现内容接收:
  2. ListView contactsView = (ListView) findViewById(R.id.contacts_view);
  3. adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, contactsList);//使用ArrayAdapter实现
  4. contactsView.setAdapter(adapter);
  5. if (ContextCompat.checkSelfPermission(this,
  6. Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED) {
  7. ActivityCompat.requestPermissions(this, new String[]{
  8. Manifest.permission.READ_CONTACTS}, 1);
  9. }
  10. else {
  11. readContacts();
  12. }
  13. //内容读取:读取联系人的信息
  14. private void readContacts() {
  15. Cursor cursor = null;
  16. try {
  17. //查询联系人数据:
  18. cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
  19. if (cursor != null){
  20. while (cursor.moveToNext()) {
  21. //获取联系人姓名:
  22. String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
  23. //获取联系人手机号
  24. String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
  25. contactsList.add(displayName + "\n" + number);
  26. }
  27. adapter.notifyDataSetChanged();
  28. }
  29. }catch (Exception e){
  30. e.printStackTrace();
  31. }
  32. finally {
  33. if (cursor != null){
  34. cursor.close();
  35. }
  36. }
  37. }

创建自己的Content provider

步骤

新建一个类继承ContentProvider(),重写6大方法,分别是:

  1. onCreate()
  2. query()
  3. delete()
  4. insert()
  5. update()
  6. getType()

项目实现

没必要继续看了。我不是专门写应用程序的,因此不需要知道具体的实现。