前言
因为以前的系统图片选择器在多选的体验上太差,或者想做一些自定义的操作,所以以前一般都是使用自定义的图片选择器或者一些功能性比较强大的第三方图片选择器。但从现在起需要改成使用系统的图片选择器,为什么这么突然?因为google早已下达了最后的期限。


能看到25年的5月28就是这个的最后期限。为什么google要这么做,近年来的更新我们都知道,google一直在规范和完善权限这块领域的内容,这一操作也只是google进一步缩紧权限的操作。
那么也可以去思考一下,未来会不会进一步收缩,比如跳H5,它会不会最终弄成只允许跳自家的浏览器,或者跳其它应用会加上严苛的限制。
startActivityForResult过期
讲系统的图片选择器之前可以先预热了解一下startActivityForResult过期的问题。这个会和获取返回的图片有一定的相关。我们平时跳出应用外的页面并且需要返回数据,比如跳到相册,返回选择的相片。以前的做法一般都是通过startActivityForResult和onActivityResult去进行配合。
其中的一个核心是requestCode和resultCode,我怎么判断onActivityResult的调用是对应哪个startActivityForResult,就是用这两个code来做区分的嘛,这个注意一下,后面会考。
回归正题,现在这个方法已经过期了,如果你在项目中使用的话,你会明显发现

那么官方把这个方法过期了,自然有提供新的方法,可以参考官网 developer.android.com/training/ba...

写个Dmeo就是
scss
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化 ActivityResultLauncher
activityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
// 处理返回结果
if (result.getResultCode() == RESULT_OK) {
Intent data = result.getData();
// 处理数据
}
});
}
arduino
Intent intent = new Intent(this, SecondActivity.class);
activityResultLauncher.launch(intent); // 启动第二个活动
这里有个需要注意的点,registerForActivityResult需要写在onCreate里面
我这里就不做演示了,那么此时你应该会发现一个问题,假如我该Activity有intent到不同页面的场景并且都有返回内容,我怎么区分此时返回的是哪个intent的,因为这个新的方式是没有requestCode去做区分的。
其实也很简单,这里的整个activityResultLauncher就可以当成一个行为的对象,如果你要跳转多个页面,那就创建多个activityResultLauncher,它内部的callback就是对应的意图
跳转系统相册进行图片选择
上面说了startActivityForResult过期了,我这里肯定直接用registerForActivityResult来实现。
kotlin
private var imagePickerLauncher: ActivityResultLauncher<Intent>? = null
fun bindActivity(activity: AppCompatActivity, callback: (Intent?) -> Unit?) {
this.activity = activity
imagePickerLauncher = activity.registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
callback.invoke(data)
}
}
}
fun select() {
val intent = Intent(Intent.ACTION_PICK)
intent.setType("image/*")
imagePickerLauncher?.launch(intent)
}
我简单封装了一个方法,直接跳相册选择图片后返回,bindActivit需要在onCreate中调用,这个上面有重点说过。
这样看似乎是没问题,但是(Android13以下)你会发现,跳到相册里面没办法多选,只能实现单选图片的场景。那怎么进行多选呢?
Android 跳系统相册选择图片
回到最开始说的正常,联系上面的方法,既然Android提出了这个政策,而我们的旧的方法又做不到多选,那官方自然会提供新的方法给我们调用。
developer.android.com/training/da...


单选
typescript
private var pickMultipleMedia1: ActivityResultLauncher<PickVisualMediaRequest>? = null
pickMultipleMedia1 = activity.registerForActivityResult(
ActivityResultContracts.PickVisualMedia()
){uri ->
callback.invoke(uri)
}
pickMultipleMedia1?.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
多选
typescript
private var pickMultipleMedia2: ActivityResultLauncher<PickVisualMediaRequest>? = null
pickMultipleMedia2 = activity.registerForActivityResult(
ActivityResultContracts.PickMultipleVisualMedia(
数量
)
){uris ->
if (uris.isNotEmpty()) {
var realUris: List < Uri? > = uris
if (uris.size > 数量){
realUris = uris.take(数量)
}
callback.invoke(realUris)
}
}
pickMultipleMedia2?.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
多选这里里面有一步判断数量的操作,这个是和版本兼容相关的,下面会进行说明。
从这里看出,在旧版本的跳转系统相册我们是使用Intent的方法去跳转,这种方式无法适配多选的场景,而Android新提供的PickVisualMedia和PickMultipleVisualMedia能让我们实现跳转系统相册并进行单选和多选。
版本兼容
没错,PickVisualMedia和PickMultipleVisualMedia存在版本兼容的问题,在Android13以下是会打开到旧页面

可以看到这种情况下也没有多选的提示,但是当随便长按一张图片之后,就能正常打开多选的场景

但是这种多选还会存在一个问题,那就是没办法限制住图片的数量,想选多少就选多少,所以上面的代码中才会写
csharp
var realUris: List < Uri? > = uris
if (uris.size > 数量){
realUris = uris.take(数量)
}
就是为了防止这种场景的发生,比如只能选3张图,这里选了10张,我在外边只拿前3张,当然这是我自己业务里面的策略,这里当然也可以做其它策略,比如超出就全丢掉。
而在Android13之后,PickMultipleVisualMedia会跳转到新相册中,此时就有比较好的体验了
