《第二行代码》第二版学习笔记(6)——内容提供器

发布于:2024-04-27 ⋅ 阅读:(30) ⋅ 点赞:(0)

内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性。

一 运行时权限

Android的权限机制,从系统的第一个版本开始就已经存在了。但其实之前Android的权限机制在保护用户安全和隐私等方面起到的作用比较有限,尤其是一些大家都离不开的常用软件,非常容易“店大欺客”。为此,Android开发团队在Android 6.0系统中引用了运行时权限这个功能,从而更好地保护了用户的安全和隐私。

2.权限分类

Android现在将所有的权限归成了三类,一类是普通权限,一类是危险权限,一类是特殊权限(不讨论)

  • 普通权限:指的是那些不会直接威胁到用户的安全和隐私的权限,对于这部分权限申请,系统会自动帮我们进行授权,而不需要用户再去手动操作了。
  • 危险权限:则表示那些可能会触及用户隐私或者对设备安全性造成影响的权限,如获取设备联系人信息、定位设备的地理位置等,对于这部分权限申请,必须要由用户手动点击授权才可以,否则程序就无法使用相应的功能。

访问:安卓完整权限列表可以查看Android系统中完整的权限列表。

3 运行时申请权限

  • 第一步就是要先判断用户是不是已经给过我们授权了。checkSelfPermission(Context,具体权限名)。
  • 没有授权的话,则需要调用ActivityCompat. requestPermissions(Activity的实例,申请的权限名,请求码)方法来向用户申请授权
public void onClick(View view) {
	if (ContextCompat.checkSelfPermission(MainActivity.this,
	        android.Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){
	    ActivityCompat.requestPermissions(MainActivity.this,
	    new String[]{android.Manifest.permission.CALL_PHONE},1);
	}else {
	    call();
	}
}

注:代码相对书本更新,Manifest.permission.CALL_PHONE改为android.Manifest.permission.CALL_PHONE 否则报错

  • 申请授权后不论申请成功还是失败都会回调onRequestPermissionsResult方法
    在这里插入图片描述
@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){
                    call();
                }else {
                    Toast.makeText(this,"You denied the permission",Toast.LENGTH_SHORT).show();
                }
                break;
            default:
        }
    }

二、内容提供器

1、 ContentResolver的基本用法

通过Context中的getContentResolver()方法获取到该类的实例。 该类提供一系列方法对数据进行CRUD操作。ContentResolver中的增删改查方法都是不接收表名参数的,而是使用一个Uri参数代替,这个参数被称为内容URI,安卓对一些URI进行了封装。

URI给内容提供器中的数据建立了唯一标识符,它主要由两部分组成:authority和path

  • authority是用于对不同的应用程序做区分的,一般采用程序包名的方式来进行命名。
  • path则是用于对同一应用程序中不同的表做区分的,通常都会添加到authority的后面。
  • 一个标准的内容Uri:content://com.example.databasetest.provider/table1,表示想调用方期望访问com.example.databasetest这个应用的table1表中的数据。
  • 如果在这个Uri后面加一个id,例如content://com.example.databasetest.provider/table1/1,期望访问table1表中id为1的数据
	Uri newUri = getContentResolver().insert(uri, values);
	
	getContentResolver().delete(uri,null,null);
	
	getContentResolver().update(uri,values,null,null);
	
	Cursor cursor = getContentResolver().query(uri, null, null,
	        null, null);
                

2、现有的内容提供器

读取和操作相应程序中的数据。如读取系统联系人,系统中有联系人列表的提供器。

  • 申请运行时权限,参照1.3部分。

  • 查询联系人数据,如下列代码所示,第一个参数为URI对象(系统对这个对象做了封装)

  • 在清单文件中声明读取系统联系人的权限

    <uses-permission android:name="android.permission.CALL_PHONE"/>
    
  • 效果图
    在这里插入图片描述

3、创建自己的内容提供器

给我们程序的数据提供外部访问接口。

2.1 创建内容提供器的步骤

  • 在com.example.databasetest包下新建MyProvider继承ContentProvider,并重写6个抽象类方法(alt+shift+enter)。

  • 在静态代码块中创建UriMatcher的实例

     static {
            uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
            uriMatcher.addURI(AUTHORITY,"book",BOOK_DIR);
            uriMatcher.addURI(AUTHORITY,"book/#",BOOK_ITEM);
            uriMatcher.addURI(AUTHORITY,"category",CATEGORY_DIR);
            uriMatcher.addURI(AUTHORITY,"category/#",CATEGORY_ITEM);
        }
    
  • 写CRUD方法

  • 写getType方法,必须以vnd开头。Uri以路径结尾,vnd后接.android.cursor.dir,Uri以id结尾,vnd后接.android.cursor.item。

    @Override
    public 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");
        switch (uriMatcher.match(uri)){
            case BOOK_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.book";
            case BOOK_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.book";
            case CATEGORY_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.category";
            case CATEGORY_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.category";
        }
        return null;
    }
  • 在清单文件中注册该provider
   <provider
      android:name=".DatabaseProvider"
      android:authorities="com.example.databasetest.provider"
      android:enabled="true"
      android:exported="true">
  </provider>

使用下列方式生成的provider,会在清单文件中自动注册。
在这里插入图片描述

2.2 跨程序数据共享

新建ProviderTets 项目,在该项目下访问DatabaseTest中数据库的数据。

代码更新:按照书上的执行报错,解决办法
在ProviderTets 的清单文件中添加如下声明:第一行是内容提供器所在的包名,第二行是内容提供器的authority。

    <queries android:name="com.example.databasetest"/>
    <queries><provider android:authorities="com.example.databasetest.provider"/></queries>

网站公告

今日签到

点亮在社区的每一天
去签到