Android --- 共享数据 -- ContentResolver

本文介绍了Android中ContentProvider和ContentResolver的概念及其作用。强调了在6.0及以上版本,针对联系人和短信等数据操作需动态申请权限。详细阐述了动态权限申请的步骤,并以读取短信为例进行说明。同时,列举了Android 6.0后需要单独申请的权限组。文章还提及了加载图片、视频和音频的相关内容,以及如何在不同Android版本中使用ActivityCompat和ContextCompat进行兼容处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介:

ContentProvider 是内容提供者
ContentResolver 内容解析者

ContentProvider 在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider 对你应用中的数据进行添删改查。
关于数据共享,以前我们学习过文件操作模式,知道通过指定文件的操作模式为Context.MODE_WORLD_READABLE 或Context.MODE_WORLD_WRITEABLE同样也可以对外共享数据。
那么,这里为何要使用ContentProvider 对外共享数据呢?是这样的,如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,如:采用xml文件对外共享数据,需要进行xml解析才能读取数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读取数据。 使用ContentProvider对外共享数据的好处是统一了数据的访问方式。
ContentProvider的原理是按照一定规则暴露自己的接口给其它应用来访问自己应用的数据(其实就是自定义增删改查接口并暴露出去,让别的应用访问自己的数据)。
ContentResolver就是按照一定规则访问内容提供者的数据(其实就是调用内容提供者自定义的接口来操作它的数据)。

系统中提供的 ContentProvider 都需要使用 ContentResolver 来操作,操作方式,
在任何一个 Context 环境下均可以使用 getContentResolver() 拿到ContentResolver 对象

查询:

private void readSms(){
    // 短信的 Uri
    Uri uri = Uri.parse("content://sms");
    // 查询的字段
    String[] columns = {"_id","address","type","body"};
    // 查询
    Cursor c = getContentResolver().query(uri,columns,null,null,null);
    StringBuilder sb = new StringBuilder();
    while(c.moveToNext()){
        int id = c.getInt(0);
        String address = c.getString(1);
        int type = c.getInt(2);
        String body = c.getString(3);
        sb.append(id).append("\t").append(address).append("\t")
            .append(type).append("\t").append(body).append("\n");
    }
    c.close();
    tvResult.setText(sb.toString());
}

注意: 6.0 以上针对部分数据(联系人,短信)需要动态申请权限

动态申请权限

1 、检测权限是否被授权

// 检测是否授权
int permissionState = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS);
    if(permissionState == PackageManager.PERMISSION_GRANTED){
    //已授权
}

2 、如果未授权则需要申请权限

requestPermissions(new String[]{Manifest.permission.READ_SMS},REQUST_READ_SMS);

3 、处理申请结果,需要在 Activity 中重写 onRequestPermissionsResult 方法

以申请读短信为例

检测和申请
// 检测当前系统是否是 6.0 以上
if(Build.VERSION.SDK_INT >= 23){
    // 检测是否授权
    int permissionState = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS);
    if(permissionState == PackageManager.PERMISSION_GRANTED){
        // 表示已经授权
        readSms();
    } else {
        // 申请权限
        requestPermissions(new String[]{Manifest.permission.READ_SMS},REQUST_READ_SMS);
    }
} else {
    readSms();
}

结果处理
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if(requestCode == REQUST_READ_SMS){
    if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
        // 授权成功
        readSms();
    }else{
        // 是否需要跟用户解释为什么要申请该权限
        if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.READ_SMS)){
            // 解释一下
            AlertDialog.Builder b = new AlertDialog.Builder(this);
            b.setTitle(" 警告 ");
            b.setMessage(" 不授权将无法显示数据 ");
            b.setPositiveButton(" 确认 ", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if(Build.VERSION.SDK_INT >= 23){
                        requestPermissions(new String[]{Manifest.permission.READ_SMS}
                        ,REQUST_READ_SMS);
                    }
                }
            });
            b.setNegativeButton(" 取消 ",null);
            b.show();
            }
        }
    }
}

[ 附 ]

Android6.0 之后需要单独申请的权限

共分为 9 组,每组只要有一个权限申请成功了,就默认整组权限都可以使用了

group:android.permission-group.CONTACTS
    permission:android.permission.WRITE_CONTACTS
    permission:android.permission.GET_ACCOUNTS
    permission:android.permission.READ_CONTACTS

group:android.permission-group.PHONE
    permission:android.permission.READ_CALL_LOG
    permission:android.permission.READ_PHONE_STATE
    permission:android.permission.CALL_PHONE
    permission:android.permission.WRITE_CALL_LOG
    permission:android.permission.USE_SIP
    permission:com.android.voicemail.permission.ADD_VOICEMAIL

group:android.permission-group.CALENDAR
    permission:android.permission.READ_CALENDAR
    permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA
    permission:android.permission.CAMERA

group:android.permission-group.SENSORS
    permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION
    permission:android.permission.ACCESS_FINE_LOCATION
    permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE
    permission:android.permission.READ_EXTERNAL_STORAGE
    permission:android.permission.WRITE_EXTERNAL_STORAGE

group:android.permission-group.MICROPHONE
    permission:android.permission.RECORD_AUDIO

group:android.permission-group.SMS
    permission:android.permission.READ_SMS
    permission:android.permission.RECEIVE_WAP_PUSH
    permission:android.permission.RECEIVE_MMS
    permission:android.permission.RECEIVE_SMS
    permission:android.permission.SEND_SMS
    permission:android.permission.READ_CELL_BROADCASTS

Android 普通权限,只需要在 AndroidManifest.xml 中声明即可

android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT

加载所有的图片

private void readImages() {
    Cursor c = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        ,null, null, null, null);
    StringBuilder sb = new StringBuilder();
    while (c.moveToNext()) {
        int id = c.getInt(c.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
        String title = c.getString(c.getColumnIndexOrThrow(MediaStore.Images.Media.TITLE));
        String data = c.getString(c.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
        sb.append(id).append("\t").append(title).append("\t").append(data).append("\n");
        // 获取缩略图
        //Bitmap thumb = MediaStore.Images.Thumbnails.getThumbnail(getContentResolver()
        , id, MediaStore.Images.Thumbnails.MICRO_KIND, null);
    }
    c.close();
    tvResult.setText(sb.toString());
}

说明: ActivityCompat 继承自 ContextCompat 均属于 v4 包中的兼容类, ActivityCompat 向低版本提供高版本 Activity 的新功能方法, ContextCompat 向低版本提
供高版本中的 Context 的新功能方法

加载视频

private void readVideo(){
    Cursor c = getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI
        , null, null, null, null);
    StringBuilder sb = new StringBuilder();
    while (c.moveToNext()) {
        int id = c.getInt(c.getColumnIndexOrThrow(MediaStore.Video.Media._ID));
        String title = c.getString(c.getColumnIndexOrThrow(MediaStore.Video.Media.TITLE));
        String data = c.getString(c.getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
        sb.append(id).append("\t").append(title).append("\t").append(data).append("\n");
        // 获取缩略图
        //if(Build.VERSION.SDK_INT >=10){
            // MediaMetadataRetriever mr = new MediaMetadataRetriever();
            // mr.setDataSource(data);
            // Bitmap b = mr.getFrameAtTime();
        //}else{
            // Bitmap thumb = ThumbnailUtils.createVideoThumbnail(data
            ,MediaStore.Images.Thumbnails.MICRO_KIND);
        // }
    }
    c.close();
    tvResult.setText(sb.toString());
}

加载所有音频

private void readAudio(){
    Cursor c = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
        , null, null, null, null);
    StringBuilder sb = new StringBuilder();
    while (c.moveToNext()) {
        int id = c.getInt(c.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
        String title = c.getString(c.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
        String data = c.getString(c.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
        sb.append(id).append("\t").append(title).append("\t").append(data).append("\n");
    }
    c.close();
    tvResult.setText(sb.toString());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值