android之Itent.ACTION_PICK Intent.ACTION_GET_CONTENT妙用

本文介绍如何在Android应用中通过Intent.ACTION_PICK和Intent.ACTION_GET_CONTENT实现选择联系人列表与文件操作,包括权限申请、启动Activity、处理结果等步骤,并提供了实例代码解析。

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

你是不是很多时候,想从弹出的电话本姓名列表中中查找到某个人,然后再获取该人的详细信息呢?

你是不是想选择从弹出的列表中选择一张图片,然后将其进行进一步的操作呢?

如果,你想,那你是不是很像知道,我们应该怎么让其弹出来一张选择列表,又应该怎么代码实现后边的操作呢?

Itent.ACTION_PICK  Intent.ACTION_GET_CONTENT 两者都可以完成类似的功能,让我们一起来看下例子:

第一:Intent.ACTION_PICK

首先添加一个权限:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
发起一个 Contact Picker
Intent intent = new Intent(Intent.ACTION_PICK, People.CONTENT_URI);
startActivityForResult(intent, PICK_CONTACT);
重写方法
@Override
public void onActivityResult(int reqCode, int resultCode, Intent data)
  { 
      super.onActivityResult(reqCode, resultCode, data); 
        switch (reqCode) {
             case (PICK_CONTACT) :     
             if (resultCode == Activity.RESULT_OK) {       
             Uri contactData = data.getData();       
             Cursor c =  managedQuery(contactData, null, null, null, null);       
             if (c.moveToFirst()) {         
                String name = c.getString(c.getColumnIndexOrThrow(People.NAME));         
                // TODO Whatever you want to do with the selected contact name.       
                                 }     
                      }     
              
      break; 
               
         }
   }

例如
String[] columns = new String[] {People.NAME};
int[] names = new int[] {R.id.row_entry};
mAdapter = new SimpleCursorAdapter(this, R.layout.mycontacts, C, columns, names);
setListAdapter(mAdapter);
第二:Intent.ACTION_GET_CONTENT
我们可以发现,其实action_get_content是通过intent中设置的type属性来判断具体调用哪个程序的。
  1. Intent intent = new Intent(Intent.ACTION_GET_CONTENT);   
  2. intent.setType("audio/*");   
  3. startActivity(Intent.createChooser(intent, "Select music"));  

 

 

执行之 会弹出一个对话框 效果为:

 

 

 

 

 

 

其实 对于这段代码 大家应该都能猜出什么意思  现自己模拟并理解之

 

 

 

[代码]

 

1. 定义TestActivity 用于根据传入Uri  播放目标

 

Java代码
  1. public class TestActivity extends Activity {   
  2.        
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {   
  5.         super.onCreate(savedInstanceState);   
  6.         setContentView(R.layout.main);   
  7.         this.setTitle("TestActivity");   
  8.            
  9.         Intent i = this.getIntent();   
  10.            
  11.         Uri u = i.getData();   
  12.            
  13.         try {   
  14.             playMusic(u);   
  15.         } catch (IllegalArgumentException e) {   
  16.             // TODO Auto-generated catch block   
  17.             e.printStackTrace();   
  18.         } catch (SecurityException e) {   
  19.             // TODO Auto-generated catch block   
  20.             e.printStackTrace();   
  21.         } catch (IllegalStateException e) {   
  22.             // TODO Auto-generated catch block   
  23.             e.printStackTrace();   
  24.         } catch (IOException e) {   
  25.             // TODO Auto-generated catch block   
  26.             e.printStackTrace();   
  27.         }   
  28.     }   
  29.        
  30.     public void playMusic(Uri uri) throws IllegalArgumentException, SecurityException, IllegalStateException, IOException{   
  31.         MediaPlayer mp = new MediaPlayer();   
  32.         mp.setDataSource(this, uri);   
  33.         mp.prepare();   
  34.         mp.start();   
  35.     }   
  36. }  

 

 

 

2. 在AndroidManifest 注册TestActivity

 

Java代码
  1. <activity android:name=".TestActivity"  
  2.                   android:label="TestActivity">   
  3.             <intent-filter>   
  4.                 <action android:name="android.intent.action.GET_CONTENT" />   
  5.                  <category android:name="android.intent.category.DEFAULT" />   
  6.                  <category android:name="android.intent.category.OPENABLE" />   
  7.                  <data android:mimeType="audio/music1" />   
  8.             </intent-filter>   
  9.         </activity>  

 

 

 

3. 使用TestActivity

 

Java代码
  1. public void sendChooser(){   
  2.         Intent intent = new Intent(Intent.ACTION_GET_CONTENT);   
  3.            
  4.         intent.setDataAndType(Uri.parse("file:///sdcard/DCIM/cc.mp3"), "audio/music1");   
  5.   
  6.         startActivity(Intent.createChooser(intent, "Select music1 app"));   
  7.     }  

 

 

4. emulator 运行截图:

 

 

此外:

   //选择图片 requestCode 返回的标识

  Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT); //"android.intent.action.GET_CONTENT"

  innerIntent.setType(contentType); //查看类型 String IMAGE_UNSPECIFIED = "image/*";

  Intent wrapperIntent = Intent.createChooser(innerIntent, null);

  ((Activity) context).startActivityForResult(wrapperIntent, requestCode);

 

  //视频

  Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT);

  innerIntent.setType(contentType); //String VIDEO_UNSPECIFIED = "video/*";

  Intent wrapperIntent = Intent.createChooser(innerIntent, null);

  ((Activity) context).startActivityForResult(wrapperIntent, requestCode);

 

  //添加音频

  Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT);

  innerIntent.setType(contentType); //String VIDEO_UNSPECIFIED = "video/*";

  Intent wrapperIntent = Intent.createChooser(innerIntent, null);

  ((Activity) context).startActivityForResult(wrapperIntent, requestCode);

 

  //录音

  Intent intent = new Intent(Intent.ACTION_GET_CONTENT);

  intent.setType(ContentType.AUDIO_AMR); //String AUDIO_AMR = "audio/amr";

  intent.setClassName("com.android.soundrecorder",

  "com.android.soundrecorder.SoundRecorder");

  ((Activity) context).startActivityForResult(intent, requestCode);

 

  //拍摄视频

  int durationLimit = getVideoCaptureDurationLimit(); //SystemProperties.getInt("ro.media.enc.lprof.duration", 60);

  Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);

  intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);

  intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, sizeLimit);

  intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, durationLimit);

  startActivityForResult(intent, REQUEST_CODE_TAKE_VIDEO);

 

  //拍照 REQUEST_CODE_TAKE_PICTURE 为返回的标识

  Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //"android.media.action.IMAGE_CAPTURE";

  intent.putExtra(MediaStore.EXTRA_OUTPUT, Mms.ScrapSpace.CONTENT_URI); // output,Uri.parse("content://mms/scrapSpace");

  startActivityForResult(intent, REQUEST_CODE_TAKE_PICTURE);


转自:http://blog.youkuaiyun.com/chenzheng_java/article/details/6266135


<think>我们正在讨论Android权限拆分配置,特别是针对`android.permission.READ_MEDIA_VISUAL_USER_SELECTED`权限。这个权限是在Android 14(API级别34)中引入的,作为隐私保护改进的一部分。 ### 1. 权限背景和用途 在Android 13中,引入了`READ_MEDIA_IMAGES`和`READ_MEDIA_VIDEO`权限,分别用于访问图片和视频。然而,用户可能希望只授予应用访问特定图片或视频的权限,而不是整个媒体库。 因此,Android 14引入了`READ_MEDIA_VISUAL_USER_SELECTED`权限,允许应用在用户通过系统选择器(例如,使用`ACTION_OPEN_DOCUMENT`或`ACTION_PICK_IMAGES`)明确选择媒体文件后,临时访问这些选定的媒体文件。 ### 2. 权限拆分(Split Permissions)概念 权限拆分是指将一个宽泛的权限拆分成更细粒度的权限,以提供更精细的控制。在这种情况下,`READ_MEDIA_VISUAL_USER_SELECTED`是`READ_MEDIA_IMAGES`和`READ_MEDIA_VIDEO`的拆分权限,用于临时访问用户选定的媒体文件。 ### 3. 配置实现 要使用这个权限,需要在应用的`AndroidManifest.xml`中声明: ```xml <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" /> ``` #### 使用场景: 1. **当应用需要访问用户选择的图片或视频时**: - 应用可以启动系统选择器(例如,使用`Intent.ACTION_PICK_IMAGES`)让用户选择媒体文件。 - 一旦用户选择了文件,应用将获得对这些文件的临时访问权限(不需要请求完整的`READ_MEDIA_IMAGES`或`READ_MEDIA_VIDEO`权限)。 2. **临时访问**: - 临时访问权限会持续一段时间(具体由系统决定),在此期间应用可以访问选定的文件。 - 如果应用需要长期访问,则仍然需要请求完整的媒体权限。 ### 4. 请求流程 1. **启动系统选择器**: ```java Intent intent = new Intent(Intent.ACTION_PICK_IMAGES); intent.setType("image/*"); // 或者 "video/*" 或混合类型 startActivityForResult(intent, REQUEST_CODE); ``` 2. **处理返回结果**: ```java @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) { if (data != null) { Uri selectedImageUri = data.getData(); // 使用这个URI读取选中的图片或视频 } } } ``` ### 5. 权限自动授予 当用户通过系统选择器选择文件后,系统会自动授予应用`READ_MEDIA_VISUAL_USER_SELECTED`权限,以便应用可以读取这些选定的文件。应用不需要显式请求这个权限(即不需要使用`requestPermissions()`)。 ### 6. 与其他权限的关系 - 如果应用同时需要访问整个媒体库(而不仅仅是用户选择的文件),则必须请求`READ_MEDIA_IMAGES`和/或`READ_MEDIA_VIDEO`权限。 - 在Android 14中,`READ_MEDIA_VISUAL_USER_SELECTED`权限是独立于`READ_MEDIA_IMAGES`和`READ_MEDIA_VIDEO`的。 ### 7. 调试和测试 - 在测试时,可以通过`adb`命令检查应用是否被授予了该权限: ```bash adb shell dumpsys package <your.package.name> | grep READ_MEDIA_VISUAL_USER_SELECTED ``` - 注意:该权限是运行时权限,因此需要针对Android 14(`targetSdkVersion` 34)进行开发。 ### 8. 兼容性 - 对于低于Android 14的设备,这个权限不可用。因此,在旧设备上,应用仍然需要请求`READ_EXTERNAL_STORAGE`(对于Android 10及以下)或`READ_MEDIA_IMAGES`/`READ_MEDIA_VIDEO`(对于Android 13)。 ### 9. 在设备策略控制器(DPC)中的使用 如果开发的是设备策略控制器(DPC)应用,并且需要处理设备管理相关的合规性,可以参考引用[1]中关于声明`ADMIN_POLICY_COMPLIANCE`的intent filter和`BIND_DEVICE_ADMIN`权限的示例。但请注意,`READ_MEDIA_VISUAL_USER_SELECTED`权限与设备管理无关,它是普通应用使用的媒体权限。 ### 总结 `android.permission.READ_MEDIA_VISUAL_USER_SELECTED`权限允许应用临时访问用户通过系统选择器选定的图片或视频,而无需请求完整的媒体库访问权限。这增强了用户隐私保护,并提供了更细粒度的权限控制。 §§ 相关问题 §§ 1. Android 14中还有哪些新的权限变化? 2. 如何为低于Android 14的设备处理媒体权限? 3. 系统选择器返回的URI如何长期访问? 4.Android 14中,如何请求完整的媒体库访问权限?</think>### Android权限拆分配置:`android.permission.READ_MEDIA_VISUAL_USER_SELECTED` #### 一、权限用途与背景 1. **核心功能** `READ_MEDIA_VISUAL_USER_SELECTED` 是 Android 14 (API 34+) 引入的细粒度媒体权限,允许应用**临时访问用户显式选择的视觉媒体文件**(图片/视频)。它解决了传统媒体权限的过度授权问题,用户无需授予整个媒体库访问权限[^1]。 2. **权限层级关系** ```mermaid graph TD A[READ_EXTERNAL_STORAGE] --> B(Android 13+) B --> C[READ_MEDIA_IMAGES] B --> D[READ_MEDIA_VIDEO] C & D --> E[Android 14+] E --> F[READ_MEDIA_VISUAL_USER_SELECTED] ``` 3. **关键特性** - **临时访问**:仅限用户通过系统选择器(如照片选择器)选定的文件 - **自动撤销**:访问权限在系统定义的时间后自动过期 - **无需弹窗**:不触发运行时权限请求对话框 #### 二、配置实现步骤 1. **声明权限** 在 `AndroidManifest.xml` 中添加: ```xml <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" /> ``` 2. **启动系统选择器** 使用 Android 14 的照片选择器 API: ```java // 启动选择器(支持多选) val pickMedia = registerForActivityResult(PickVisualMedia()) { uris -> // 处理用户选择的媒体URI } pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo)) ``` 3. **访问选定文件** 通过返回的 URI 访问媒体内容: ```kotlin contentResolver.openInputStream(uri).use { stream -> // 读取媒体数据 } ``` #### 三、权限处理机制 1. **自动授权流程** ```mermaid sequenceDiagram 用户->>系统选择器: 选择图片/视频 系统选择器->>应用: 返回内容URI 系统->>权限控制器: 自动授予临时权限 权限控制器-->>应用: 通过ContentResolver访问 ``` 2. **访问范围限制** - ✅ 可访问用户选择的精确文件 - ❌ 无法访问同目录其他文件 - ❌ 无法访问媒体库元数据 3. **权限有效期** - 前台服务:持续到应用进程结束 - 后台访问:最长 1 小时(系统可调整) #### 四、兼容性处理 ```java if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { // 使用 READ_MEDIA_VISUAL_USER_SELECTED } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // 回退到 READ_MEDIA_IMAGES/VIDEO } else { // 使用 READ_EXTERNAL_STORAGE } ``` #### 五、调试验证方法 1. 检查权限状态: ```bash adb shell dumpsys package com.your.package | grep READ_MEDIA_VISUAL ``` 2. 测试权限过期: ```bash adb shell am broadcast -a android.intent.action.TIME_SET ``` #### 六、最佳实践 1. **组合使用策略** ```kotlin val hasFullAccess = ContextCompat.checkSelfPermission( this, READ_MEDIA_IMAGES) == PERMISSION_GRANTED if (!hasFullAccess) { // 启动选择器获取临时访问 pickMedia.launch(...) } ``` 2. **数据刷新处理** 实现 `ContentObserver` 监听媒体变化: ```java contentResolver.registerContentObserver( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, yourObserver ); ``` > 注意:此权限需配合 `android.permission.FOREGROUND_SERVICE` 在后台使用[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值