不要再用onActivityResult了,用更高级更方便的。
启动一个activity需要一个laucher,这个laucher由registerForActivityResult返回,这个方法需要两个参数,一个参数为一个抽象类——ActivityResultContract<I, O>的实现,另一个参数是一个函数式接口的实现(用一个lambda表达式来代替)。
第一个参数要实现两个方法:
public abstract class ActivityResultContract<I, O> {
/** Create an intent that can be used for {@link Activity#startActivityForResult} */
public abstract @NonNull Intent createIntent(@NonNull Context context,
@SuppressLint("UnknownNullness") I input);
/** Convert result obtained from {@link Activity#onActivityResult} to O */
@SuppressLint("UnknownNullness")
public abstract O parseResult(int resultCode, @Nullable Intent intent);
第一个方法是配置结合input配置intent, 第二个方法是从intent取出数据返回。
第二个参数是对从intent取出的数据的处理。
技巧:官方为我们提供了很多便捷的实现好的第一个参数:
预定义的Contract
大伙都看出来,新的Activity Results API使用起来好像有点麻烦,每次都得定义Contract。Google肯定考虑到了这个问题的,于是,Google 预定义了很多Contract,
把你们能想到的使用场景基本上都想到了,它们都定义在类ActivityResultContracts中,有以下这些Contract:
StartActivityForResult()
RequestMultiplePermissions()
RequestPermission()
TakePicturePreview()
TakePicture()
TakeVideo()
PickContact()
CreateDocument()
OpenDocumentTree()
OpenMultipleDocuments()
OpenDocument()
GetMultipleContents()
GetContent()
下面分别介绍一下这些Contract:
StartActivityForResult: 通用的Contract,不做任何转换,Intent作为输入,ActivityResult作为输出,这也是最常用的一个协定。
RequestMultiplePermissions: 用于请求一组权限
RequestPermission: 用于请求单个权限
TakePicturePreview: 调用MediaStore.ACTION_IMAGE_CAPTURE拍照,返回值为Bitmap图片
TakePicture: 调用MediaStore.ACTION_IMAGE_CAPTURE拍照,并将图片保存到给定的Uri地址,返回true表示保存成功。
TakeVideo: 调用MediaStore.ACTION_VIDEO_CAPTURE 拍摄视频,保存到给定的Uri地址,返回一张缩略图。
PickContact: 从通讯录APP获取联系人
GetContent: 提示用选择一条内容,返回一个通过ContentResolver#openInputStream(Uri)访问原生数据的Uri地址(content://形式) 。默认情况下,它增加了Intent#CATEGORY_OPENABLE, 返回可以表示流的内容。
CreateDocument: 提示用户选择一个文档,返回一个(file:/http:/content:)开头的Uri。
OpenMultipleDocuments: 提示用户选择文档(可以选择多个),分别返回它们的Uri,以List的形式。
OpenDocumentTree: 提示用户选择一个目录,并返回用户选择的作为一个Uri返回,应用程序可以完全管理返回目录中的文档。
具体可参考:https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContracts
比如说,打开联系人列表选择一个联系人的ActivityResultContracts的实现为:
/**
* An {@link ActivityResultContract} to request the user to pick a contact from the contacts
* app.
* <p>
* The result is a {@code content:} {@link Uri}.
*
* @see ContactsContract
*/
public static final class PickContact extends ActivityResultContract<Void, Uri> {
@NonNull
@Override
public Intent createIntent(@NonNull Context context, @Nullable Void input) {
return new Intent(Intent.ACTION_PICK).setType(ContactsContract.Contacts.CONTENT_TYPE);
}
@Nullable
@Override
public Uri parseResult(int resultCode, @Nullable Intent intent) {
if (intent == null || resultCode != Activity.RESULT_OK) return null;
return intent.getData();
}
}
附上一个实例:
private val aLauncher =
registerForActivityResult(ActivityResultContracts.PickContact()) { uri: Uri? ->
// Handle the returned Uri
//crimesuspect启动activity的注册laucher
val queryFields = arrayOf(ContactsContract.Contacts.DISPLAY_NAME)
val cursor =
uri?.let {
requireActivity().contentResolver.query(
it,
queryFields,
null,
null,
null
)
}
cursor?.use {
if (it.count > 0) {
it.moveToFirst()
val suspect = it.getString(0)
crime.suspect = suspect
crimeDetailViewModel.saveCrime(crime)
binding.crimeSuspect.text = suspect
}
}
}
设置监听器的时候:binding.crimeSuspect.setOnClickListener {
aLauncher.launch()
}