Android Activity Result API

简介: Android Activity Result API

startActivityForResult问题

startActivityForResult(Intent(this, SecondActivity::class.java), REQ_CODE)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQ_CODE) {
        if (resultCode == Activity.RESULT_OK) {
            data?.let {
                val value: String? = data.getStringExtra("hello")
                log(value!!)
            }
        }
    }
}

startActivityForResult()onActivityResult() 导致代码嵌套较多、耦合度高、难以维护等问题。

Google可能意识到该问题,推荐使用Activity Results API。

为什么强烈建议使用Activity Results API

官方解释

虽然所有 API 级别的 Activity 类均提供底层 startActivityForResult()onActivityResult() API,但我们强烈建议您使用 AndroidX Activity和 Fragment中引入的 Activity Result API。

Activity Result API 提供了用于注册结果、启动结果以及在系统分派结果后对其进行处理的组件。

启动一个 activity(无论是本应用中的 activity 还是其他应用中的 activity)不一定是单向操作,也可以启动另一个 activity 并接收返回的结果。

在启动 activity 以获取结果时,可能会出现您的进程和 activity 因内存不足而被销毁的情况;如果是使用相机等内存密集型操作,几乎可以确定会出现这种情况。

因此,Activity Result API 会将结果回调从您之前启动另一个 activity 的代码位置分离开来。由于在重新创建进程和 activity 时需要使用结果回调,因此每次创建 activity 时都必须无条件注册回调,即使启动另一个 activity 的逻辑仅基于用户输入内容或其他业务逻辑也是如此。

通俗解释

常见的场景是调用系统相机、调用相册获取照片、调用通讯录、获取部分特殊权限等,传统方式通常是通过 Intent 携带数据,然后使用 startActivityForResult 方法来启动下一个 Activity,然后通过 onActivityResult 来接收返回的数据。

传统方式的问题在于:

1、在启动 activity 以获取结果时,可能会出现进程和 activity 因内存不足而被销毁的情况。

2、onActivityResult 回调方法嵌套耦合严重,逻辑混乱导致难以维护。

Activity Result API使用

主要有两种使用方式:

1、调用系统内置ActivityResultContract

2、调用自定义ActivityResultContract

方式一,系统内置ActivityResultContract使用

Android系统内置了常用Contract,部分列举如下

StartActivityForResult():通用Contract

RequestMultiplePermissions():申请一组权限

RequestPermission():申请单个权限

TakePicturePreview():拍照,返回Bitmap

TakePicture():拍照,保存指定Uri地址,返回true表示保存成功

TakeVideo():拍视频,保存指定Uri地址,返回一张缩略图

PickContact():从通讯录获取联系人

CreateDocument():选择一个文档,返回Uri

OpenDocumentTree():选择一个目录,返回Uri

OpenMultipleDocuments(),选择多个文档,返回多个Uri

GetContent():选择一条内容,返回Uri

StartActivityFoResult

启动一个Activity并返回数据。

注册协议

private val activityLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
    if (it.resultCode == Activity.RESULT_OK) {
        val data = it.data
        data?.apply {
            val name = getStringExtra("name")
            val age = getIntExtra("age", 0)
            val address = getStringExtra("address")
            textView.text = "name:$name age:$age address:$address"
        }
    }
}

启动

activityLauncher.launch(
    Intent(this, ThirdActivity::class.java).apply {
        putExtra("name", "小花")
        putExtra("age", 38)
        putExtra("address", "guangzhou")
    }
)

RequestPermission

申请单个权限。

注册协议

private val permissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
    if (it) {
        Toast.makeText(mContext, "权限申请-成功", Toast.LENGTH_SHORT).show()
    } else {
        Toast.makeText(mContext, "权限申请-失败", Toast.LENGTH_SHORT).show()
    }
}

启动

permissionLauncher.launch(Manifest.permission.CAMERA)

RequestMultiplePermissions

申请多个权限。

注册协议

private val multiPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { 
    it ->
    it.forEach {
        if (it.value) {
            Toast.makeText(mContext, "${it.key} 申请权限-成功", Toast.LENGTH_SHORT).show()
        } else {
            Toast.makeText(mContext, "${it.key} 申请权限-失败", Toast.LENGTH_SHORT).show()
        }
    }
}

启动

multiPermissionLauncher.launch(
    arrayOf<String>(
        Manifest.permission.CAMERA,
        Manifest.permission.CALL_PHONE,
        Manifest.permission.ACCESS_FINE_LOCATION
    )
)

TakePicturePreview

拍照。

注册协议

private val takePicturePreviewLauncher =
registerForActivityResult(ActivityResultContracts.TakePicturePreview()) {
    Toast.makeText(mContext, "Bitmap大小:${it.byteCount}", Toast.LENGTH_SHORT).show()
}

启动

takePicturePreviewLauncher.launch(null)

方式二,自定义ActivityResultContract使用

Activity Results API有三个重要的类:

ActivityResultContract:协议,这是一个抽象类,定义如何传递数据和如何接收数据,

ActivityResultLauncher:启动器,相当于以前的startActivityForResult()

ActivityResultCallback:结果回调,相当于以前的onActivityResult()

官方说明:

位于 ComponentActivityFragment 中时,Activity Result API 会提供 registerForActivityResult() API,用于注册结果回调。

registerForActivityResult() 接受 ActivityResultContractActivityResultCallback 作为参数,并返回 ActivityResultLauncher,供您用来启动另一个 activity。

ActivityResultContract 定义生成结果所需的输入类型以及结果的输出类型。这些 API 可为拍照和请求权限等基本 intent 操作提供默认协定。您还可以创建自己的自定义协定

ActivityResultCallback 是单一方法接口,带有 onActivityResult() 方法,可接受 ActivityResultContract 中定义的输出类型的对象。

创建待启动Activity

class SecondActivity : AppCompatActivity() {
    private lateinit var textView: TextView
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
        textView = findViewById(R.id.textView)
        val name = intent.getStringExtra("name")
        textView.text = name
    }
    fun finishClick(view: View) {
        setResult(Activity.RESULT_OK, Intent().apply {
            putExtra("result", "hello ActivityResult")
        })
        finish()
    }
}

定义协议

class MyContract : ActivityResultContract<String, String>() {
    override fun createIntent(context: Context, input: String?): Intent {
        return Intent(context, SecondActivity::class.java).apply {
            putExtra("name", input)
        }
    }
    override fun parseResult(resultCode: Int, intent: Intent?): String? {
        val result = intent?.getStringExtra("result")
        return if (resultCode == Activity.RESULT_OK) {
            result
        } else {
            null
        }
    }
}

注册协议

private val launcher = registerForActivityResult(MyContract()) {
    textView.text = it
}

跳转

launcher.launch("hello world")

结果

textView.text被设置成"hello ActivityResult"

相关文章
|
3月前
|
Android开发 开发者
Android UI设计: 请解释Activity的Theme是什么,如何更改应用程序的主题?
Android UI设计: 请解释Activity的Theme是什么,如何更改应用程序的主题?
44 1
|
3月前
|
数据库 Android开发 开发者
Android基础知识:请解释Activity的生命周期。
Android基础知识:请解释Activity的生命周期。
45 2
|
6月前
|
存储 SQL 人工智能
Android Activity启动流程一:从Intent到Activity创建
Android Activity启动流程一:从Intent到Activity创建
|
8月前
|
定位技术 API 开发工具
Android 按照步骤接入百度地图API,定位显示不了解决办法
Android 按照步骤接入百度地图API,定位显示不了解决办法
232 0
|
2月前
|
Android开发
[Android 四大组件] --- Activity
[Android 四大组件] --- Activity
22 1
|
3月前
|
Android开发
Android基础知识:什么是Fragment?与Activity的区别是什么?
Android基础知识:什么是Fragment?与Activity的区别是什么?
293 54
|
4月前
|
XML 安全 Java
Android Studio App开发入门之活动Activity中为活动补充附加信息讲解及实战(附源码 超详细必看)
Android Studio App开发入门之活动Activity中为活动补充附加信息讲解及实战(附源码 超详细必看)
36 0
|
4月前
|
Android开发
Android Studio App开发入门之在活动之间传递消息(附源码 超详细必看)(包括显示和隐式Intent,向上一个和下一个Activity发送数据)
Android Studio App开发入门之在活动之间传递消息(附源码 超详细必看)(包括显示和隐式Intent,向上一个和下一个Activity发送数据)
46 0
|
4月前
|
Android开发
Android Studio APP开发入门之活动Activity中启停活动页面的讲解及实战(附源码,包括Activity的启动结束、生命周期、跳转等)
Android Studio APP开发入门之活动Activity中启停活动页面的讲解及实战(附源码,包括Activity的启动结束、生命周期、跳转等)
41 0
|
5月前
|
Android开发
安卓activity管理器
安卓activity管理器
27 0