美文网首页
Android Activity Result API

Android Activity Result API

作者: GameProgramer | 来源:发表于2022-04-13 17:23 被阅读0次

    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"

    相关文章

      网友评论

          本文标题:Android Activity Result API

          本文链接:https://www.haomeiwen.com/subject/iipasrtx.html