一、概念
当 appcompat ≥ 1.3.0 的时候,startActivityForResult() 和 requestPermissions() 都已经被废弃,转而推荐更方便简洁的 Activity Result API。
| registerForActivityResult( ) | public final <I, O> ActivityResultLauncher<I> registerForActivityResult( 注册一个Activity结果的监听,参数一contract类型对应不同的需求,参数二是一个Lambda当有回调的时候会显示在这里。 |
| Contract名称及作用 | |
| StartActivityForResult() | 开启Activity |
| StartIntentSenderForResult() | |
| RequestPermission() | 申请权限。 |
| RequestMultiplePermissions() | 申请多个权限。 |
| TakePicturePreview() | 调用手机自带相机拍照,拍摄后有确认和重拍选项,确认后得到这张照片的Bitmap对象。 |
| TakePicture() | 调用手机自带相机拍照,拍摄后有确认和重拍选项,确认后保存到指定的 Uri,返回true表示保存成功。 |
| TakeVideo() | 调用系统自带相机录像,保存到指定的Uri,返回一张缩略图。 |
| PickContact() | 从通讯录APP中获取联系人。 |
| GetContent() | 选择一个内容,返回Uri。 |
| GetMultipleContents() | 选择多个内容,返回多个Uri。 |
| OpenDocument() | 选择一个文件,返回Uri。 |
| OpenMultipleDocuments() | 选择多个文件,返回多个Uri。 |
| OpenDocumentTree() | 选择一个目录(文件夹),返回Uri。 |
| CreateDocument() | 创建一个文件,返回Uir。 |
| PickVisualMedia() | 通过系统媒体选择器选择单张图片/视频(Android 13新增,11(API33)及以上可用) |
| PickMultipleVisualMedia() | 通过系统媒体选择器选择多张图片/视频(Android 13新增,11(API33)及以上可用) |
二、使用
2.1 Activity之间传递数据 StartActivityForResult()
2.1.1 A→B 原来写法
class FirstActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
val intent = Intent(this, SecondActivity::class.java)
startActivityForResult(intent, 1)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
1 -> {
if (resultCode == RESULT_OK) {
val data = data?.getStringExtra("data")
// Handle data from SecondActivity
}
}
}
}
}
2.1.2 A→B 现在写法
class FirstActivity : AppCompatActivity() {
private val requestDataLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
val data = result.data?.getStringExtra("data")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
val intent = Intent(this, SecondActivity::class.java)
requestDataLauncher.launch(intent)
}
}
2.1.3 B→A 写法没变
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
val intent = Intent()
setResult(RESULT_OK, intent)
finish()
}
}
2.2 请求权限
2.2.1 单个权限 RequestPermission()
class MyActivity : AppCompatActivity() {
private val permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
takePic()
} else {
Toast.makeText(APP.context, "相机权限被拒绝", Toast.LENGTH_SHORT).show()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
button.setOnClickListener {
permissionLauncher.launch(Manifest.permission.CAMERA)
}
//判断是否有权限
if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) {}
//是否显示权限说明(只有第一次点拒绝后才会返回true)
if ( shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) ) {}
}
}
2.2.2 多个权限 RequestMultiplePermissions()
class MainActivity : AppCompatActivity() {
private val requestMultiplePermissions = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions -> //类型是 Map<String, Boolean>
permissions.entries.forEach {
//TODO...
}
}
override fun onCreate(savedInstanceState: Bundle?) {
requestMultiplePermissions.launch(
arrayOf(
Manifest.permission.BLUETOOTH,
Manifest.permission.NFC,
)
)
}
}
2.3 文件操作
2.3.1 获取文件 GetContent()
class MainActivity : AppCompatActivity() {
private val requestUriLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
if(uri != null) {
//将uri转为输入流来读取文件
val inputStream = contentResolver.openInputStream(uri)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
requestUriLauncher.launch("image/*") //只显示图片
}
}
2.3.2 写入文件 CreateDocument()
class MainActivity : AppCompatActivity() {
private val createDocument = registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { uri ->
if (uri != null) {
//将uri转为输出流来写入文件
val outputStream = contentResolver.openOutputStream(uri)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
createDocument.launch("demo.txt")
}
}
2.3.3 选择目录(选择文件夹) OpenDocumentTree()
class TestActivity : AppCompatActivity() {
private val openTree = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
//uri转File后使用
uri?.path?.let {
val directory = File(it)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
openTree.launch(null) //可传入默认目录uri
}
}
2.4 拍照并获取Bitmap TakePicturePreview()
class MainActivity : AppCompatActivity() {
private val takePictureLauncher = registerForActivityResult(ActivityResultContracts.TakePicturePreview()) { bitmap ->
//TODO...
}
override fun onCreate(savedInstanceState: Bundle?) {
takePictureLauncher.launch(null)
}
}
2.5 通过系统媒体选择器选取图片/视频
Android 13 之前还是通过应用内置的图片选择器来实现业务功能,13 之后的版本仅使用系统内置的图片选择器,完全弃用 READ_EXTERNAL_STORAGE 权限。
private val pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
if (uri != null) {
//TODO
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_result)
//选择图片或视频
pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageAndVideo))
//仅选择图片
pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
//仅选择视频
pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.VideoOnly))
//仅选择 Gif 图片
pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.SingleMimeType("image/gif")))
}
三、自定义 Contract
继承 ActivityResultContract 类,指定输入参数和输出参数的泛型,重写 createIntent() 用于创建 Intent 发起动作,重写 parseResult() 用于解析响应的结果并作为输出参数返回到 Lambda 中。
class GetDataFromSecondActivity : ActivityResultContract<Void, String?>() {
override fun createIntent(context: Context, input: Void?): Intent {
return Intent(context, SecondActivity::class.java)
}
override fun parseResult(resultCode: Int, intent: Intent?): String? {
if (resultCode == Activity.RESULT_OK) {
if (intent != null) {
return intent.getStringExtra("data")
}
}
return null
}
}
class MainActivity : AppCompatActivity() {
private val getDataLauncher = registerForActivityResult(GetDataFromSecondActivity()) { data ->
//TODO...
}
override fun onCreate(savedInstanceState: Bundle?) {
getDataLauncher.launch(null)
}
}
本文介绍Android中ActivityResult API的使用方法,包括启动Activity、请求权限等场景,并提供自定义Contract的示例。
969

被折叠的 条评论
为什么被折叠?



