Activity 结果 API 的 ActivityResultLauncher launch() 方法不仅会调用合约的 createIntent() 方法,还会调用 parseResult()

Posted

技术标签:

【中文标题】Activity 结果 API 的 ActivityResultLauncher launch() 方法不仅会调用合约的 createIntent() 方法,还会调用 parseResult()【英文标题】:Activity result API's ActivityResultLauncher launch() method causes calling not only contract's createIntent() method but also parseResult() 【发布时间】:2021-08-11 07:38:50 【问题描述】:

我在 ActivityA 上,尝试使用字符串输入启动 ActivityB,进行一些工作,然后将字符串输出返回给 ActivityA。我创建了 Activity Result API 帮助程序类,基于 tutorial 和 ActivityResultContract(都在下面列出)。我在 ActivityA 的 onCreate() 方法中注册活动结果:

private lateinit var linkLauncher: ActivityResultHandler<String, String?>

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    linkLauncher = ActivityResultHandler(this, extWebLinkAction, GetExtWebLinkContract())

问题是当我调用 linkLauncher.execute() 方法,而该方法又调用 ActivityResultLauncher 的 launch() 方法时,这两个合约方法都在 ActivityB 启动之前被调用。

这是我尝试将结果从 ActivityB 返回到 ActiviteA 的方式:

setResult(Activity.RESULT_OK, Intent().apply 
        putExtra(LINK_TRANSPORT_EXTRA, link)
)

提到的类的列表。

助手类:

import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.ActivityResultRegistry
import androidx.activity.result.contract.ActivityResultContract
import androidx.lifecycle.LifecycleOwner
import java.util.*

interface IActivityResult<I> 
    fun execute(input: I)


class ActivityResultHandler<I, O>(
    private val activity: ComponentActivity,
    private val func: (O) -> Unit,
    private val contract: ActivityResultContract<I, O>
) : IActivityResult<I> by ActivityResultHandlerImpl(
    activity.activityResultRegistry,
    activity,
    func,
    contract
) 
    private class ActivityResultHandlerImpl<I, O>(
        private val registry: ActivityResultRegistry,
        private val lifecycleOwner: LifecycleOwner,
        private val func: (O) -> Unit,
        private val contract: ActivityResultContract<I, O>
    ): IActivityResult<I> 

        private val callback =  ActivityResultCallback<O>  output ->
            func(output)
        

        private var resultLauncher: ActivityResultLauncher<I>
            = registry.register(UUID.randomUUID().toString(), lifecycleOwner, contract, callback)

        override fun execute(input: I) 
            resultLauncher.launch(input)
        

    

这是我的ActivityResultContract

import android.app.Activity
import android.content.Context
import android.content.Intent
import androidx.activity.result.contract.ActivityResultContract
import com.zultys.mobiledroid.mvvm.ui.chat.group.GroupActivity
import com.zultys.mobiledroid.mvvm.ui.profile.extweb.ExtWebLinkFragment
import com.zultys.mobiledroid.utils.extensions.logd

class GetLinkContract: ActivityResultContract<String, String?>() 
    override fun createIntent(context: Context, input: String): Intent =
        context.intentFor<ActivityB>
               .newTask()
               .putExtra(GROUP_ID_EXTRA, groupId)

    override fun parseResult(resultCode: Int, intent: Intent?): String? =
        when 
            resultCode != Activity.RESULT_OK -> null
            else -> intent?.getStringExtra(LINK_TRANSPORT_EXTRA)
        

【问题讨论】:

请注意,您的助手类对UUID.randomUUID().toString() 的使用绝对不正确,并且特别破坏了在进程死亡和重新创建或配置更改后接收活动结果的能力。你应该扔掉整个助手,只剩下follow the guide。 感谢您的评论。这一点很重要。你能检查一下我的代码还有什么问题吗?为什么 parseResult() 在 createIntent() 之后被调用? 【参考方案1】:

parseResult()createIntent() 之后被调用的原因是createIntent() 方法中的.newTask() 标志。此外,正如 ianhanniballake 所说,密钥不应该是随机的。

【讨论】:

以上是关于Activity 结果 API 的 ActivityResultLauncher launch() 方法不仅会调用合约的 createIntent() 方法,还会调用 parseResult()的主要内容,如果未能解决你的问题,请参考以下文章

Activity之间的跳转:

activity--常见属性总结

自制WheelView沉浸式菜单及Dialog样式Activit

activit的切换

Android startActivityForResult和onActivityResult的基本用法

在服务中访问 Google Play 服务位置 API