首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >带有深度链接的Android导航组件: onNewIntent多次调用

带有深度链接的Android导航组件: onNewIntent多次调用
EN

Stack Overflow用户
提问于 2020-05-22 09:28:14
回答 5查看 7.2K关注 0票数 15

这一次,我需要您的帮助,在使用android导航组件与深度链接。

我一直在跟踪这个文档,片段和深度链接之间的连接工作得很好。

问题来自于接收深度链接的活动。在我的例子中,我设置了android:launchMode="singleTask“

代码语言:javascript
代码运行次数:0
运行
复制
<activity android:name=".features.welcome.WelcomeActivity"
    android:launchMode="singleTask">
     <nav-graph android:value="@navigation/welcome_nav_graph" />
</activity>

override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)
    Timber.d("onNewIntent: $intent with activity: $this")
    navController.handleDeepLink(intent)
}

通过这种配置,我注意到了一些奇怪的行为:

每次单击深度链接时,WelcomeActivity都会收到两次onNewIntent调用。甚至有时还创建了新的活动实例。喜欢

1_对象1-onNewIntent

2_对象1-onNewIntent

3_ object2-onCreate

这里有一些日志:

第一次发射 onCreate:意图{ flg=0x10000000 cmp={applicationId}/{package}.WelcomeActivity }具有活动:{package}.WelcomeActivity@4adbef0 开深链 onNewIntent: act=android.intent.action.VIEW {act=android.intent.action.VIEW cat=android.intent.category.BROWSABLE dat=链接)… flg=0x10010000 cmp={applicationId}/{package}.WelcomeActivity (已附加)}与活动:{package}.WelcomeActivity@4adbef0 onNewIntent:意图{ act=android.intent.action.VIEW cat=android.intent.category.BROWSABLE dat=链接}..。.具有活动的flg=0x1001c000 cmp={applicationId}/{package}.WelcomeActivity (有额外的)}:{applicationId}.WelcomeActivity@4adbef0 onCreate:意图{ act=android.intent.action.VIEW cat=android.intent.category.BROWSABLE dat=链接}..。.具有活动的flg=0x1001c000 cmp={applicationId}/{package}.WelcomeActivity (有额外的)}:{applicationId}.WelcomeActivity@b77c6b 关闭应用程序并打开深度链接 onCreate:意图{ act=android.intent.action.VIEW cat=android.intent.category.BROWSABLE dat=链接}..。.具有活动的flg=0x10018000 cmp={applicationId}/{package}.WelcomeActivity (有额外的)}:{applicationId}.WelcomeActivity@b78f4df onNewIntent:意图{ act=android.intent.action.VIEW cat=android.intent.category.BROWSABLE dat=链接}..。.具有活动的flg=0x1001c000 cmp={applicationId}/{package}.WelcomeActivity (有额外的)}:{applicationId}.WelcomeActivity@b78f4df onCreate:意图{ act=android.intent.action.VIEW cat=android.intent.category.BROWSABLE dat=链接}..。.flg=0x1001c000 cmp={applicationId}/{package}.WelcomeActivity (有附加)}和{package}.WelcomeActivity@dfe87b2

更新:

1 -It似乎与这个问题无关。我注意到默认启动模式也是如此。

2- navController.navigate(intent.dataString.toUri())似乎运行良好。所以我想问题是navController.handleDeepLink(意图)。

EN

回答 5

Stack Overflow用户

发布于 2020-08-07 07:00:48

onNewIntent上的回调第一次到达时,只需设置标志intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);并将突变的意图传递给handleDeepLink(intent);

此标志消除了onNewIntent回调的第二次到达,原因是重新连接到现有的Activity (完全重构到所需的深度链接目的地的后台跟踪),而不是启动新的Activity

详细信息在handleDeepLink方法的源代码中。

票数 12
EN

Stack Overflow用户

发布于 2020-05-22 13:42:59

通过测试不同的更改,我得出的结论是,“navController.handleDeepLink(意图)”是导致这种奇怪行为的原因。

这就是我试过的:

我从导航中删除了deepLink,深层链接正常工作(我手动添加了deepLink ):使用singleTask,如果活动已经创建,那么onNewIntent只会被调用一次。如果未创建活动,则调用onCreate。

这方面的另一个问题是,navController.handleDeepLink(意图)将在onCreate中自动调用(您可以在javadocs中检查它)。当调用onNewIntent时,您需要调用navController.handleDeepLink(意图)。

我决定尝试“导航(Uri deepLink)”从NavController,我看到这是正常工作(在第一段中描述的行为)。有了这个替代方法,我决定做一些修改:

代码语言:javascript
代码运行次数:0
运行
复制
class WelcomeActivity : AppCompatActivity(){

      private val navController by lazy { findNavController(R.id.nav_host_fragment) }

      private var deepLinkData: Uri? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Timber.d("onCreate: $intent  with activity: $this")
        val data = intent.data
        intent.data = null
        setContentView(R.layout.activity_welcome)
        handleDeepLink(data)
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        Timber.d("onNewIntent: $intent with activity: $this")
        setIntent(intent)
        val data = intent?.data
        handleDeepLink(data)
    }

    private fun handleDeepLink(uri: Uri?) {
        //TODO: there is an issue that will cause onNewIntent to be called twice when the activity is already present.
        if (uri != null && deepLinkData.toString() != uri.toString() && navController.graph.hasDeepLink(uri)) {
            //possible deep link for LoginFragment
            deepLinkData = uri
            navController.navigate(uri)
        }
    }

}

注意onCreate中的这个代码块是很重要的:

代码语言:javascript
代码运行次数:0
运行
复制
val data = intent.data
intent.data = null

这样做的原因是,如果我需要阻止“navController.handleDeepLink(意图)”被调用,因为如果存在该信息,就会自动调用它,从而导致这种奇怪的行为。

navController.graph.hasDeepLink( uri )将帮助您查看您的图形是否能够处理那个uri。如果您不使用它,那么“导航(Uri deepLink)”将引发异常。

如果你遇到同样的问题,希望它能帮助你。如果你对此有更多的见解,请留下一些评论。

票数 10
EN

Stack Overflow用户

发布于 2020-07-27 11:52:53

当单击隐式深度链接时,就会有意图地设置FLAG_ACTIVITY_NEW_TASK。并且,根据文档,将重新创建后台,使其处于良好状态。请参阅这里的文档隐式深链

如果您不想要这种行为,并且不想更改意图标志,您可以自己处理深度链接,而不是将它传递给导航组件。因此,如果您使用的是AdvancedNavigationSample,您需要删除handledeeplink并按照方向使用findNavController().navigate()

另外,请记住将launcher活动的启动模式设置为singleTask,以便在单击“深度链接”或“通知”时接收新的意图。

  1. 将示例中的NavController.handledeeplink()替换为
代码语言:javascript
代码运行次数:0
运行
复制
fun BottomNavigationView.navigateDeeplink(
    navGraphIds: List<Int>,
    fragmentManager: FragmentManager,
    containerId: Int,
    uri: Uri
) {
    navGraphIds.forEachIndexed { index, navGraphId ->
        val fragmentTag = getFragmentTag(index)

        // Find or create the Navigation host fragment
        val navHostFragment = obtainNavHostFragment(
            fragmentManager,
            fragmentTag,
            navGraphId,
            containerId
        )
        // Handle deeplink
        val canHandleDeeplink = navHostFragment.navController.graph.hasDeepLink(uri)

        if (canHandleDeeplink) {
            if (selectedItemId != navHostFragment.navController.graph.id) {
                selectedItemId = navHostFragment.navController.graph.id
            }
            navHostFragment.lifecycleScope.launchWhenResumed {
                // Wait for fragment to restore state from backStack
                // otherwise navigate will be ignored
                // Ignoring navigate() call: FragmentManager has already saved its state
                navHostFragment.navController.navigateOnce(uri)
            }
        }
    }
}
  1. intent.data存储在变量中,并将其设置为null,这样导航组件就无法处理它。在onHandleNewIntent中也做同样的事情
  2. 将此深度链接传递给底部导航以处理。如果应用程序已经在运行,您可以使用上面的函数直接导航到目的地。

完整的解决方案是在这个示例上实现的。

优点:

  1. 您可以以相同的方式直接处理通知单击。从操作中创建一个深度链接,并在intent.data中PendingIntent中传递它。
  2. 您可以根据需要验证和更改深度链接。就像用户没有被记录一样,它直接进入登录活动,或者移到指定的目的地。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61951850

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档