这一次,我需要您与使用带有深层链接的android导航组件有关的帮助。
我一直在关注documentation,并且fragment和Deeplink之间的连接正常。
问题在于接收深度链接的活动。就我而言,我设置了android:launchMode =“ singleTask”
<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_ object1-onNewIntent
2_ object1-onNewIntent
3_ object2-onCreate
这里有一些日志:
首次启动
onCreate:意图{flg = 0x10000000 具有活动的cmp = {applicationId} / {package} .WelcomeActivity}: {package}。WelcomeActivity@ 4adbef0
打开深层链接
onNewIntent:意图{act = android.intent.action.VIEW cat = [android.intent.category.BROWSABLE] dat = https:// {depp_link} ... flg = 0x10010000 cmp = {applicationId} / {package}。WelcomeActivity(具有 活动):{package} .WelcomeActivity @ 4adbef0
onNewIntent:意图{act = android.intent.action.VIEW cat = [android.intent.category.BROWSABLE] dat = https:// {depp_link} ... flg = 0x1001c000 cmp = {applicationId} / {package}。WelcomeActivity(具有 活动):{package} .WelcomeActivity @ 4adbef0
onCreate:意图{act = android.intent.action.VIEW cat = [android.intent.category.BROWSABLE] dat = https:// {depp_link} ... flg = 0x1001c000 cmp = {applicationId} / {package}。WelcomeActivity(具有 活动):{package} .WelcomeActivity @ b77c6b
杀死该应用并打开深层链接
onCreate:意图{act = android.intent.action.VIEW cat = [android.intent.category.BROWSABLE] dat = https:// {depp_link} ... flg = 0x10018000 cmp = {applicationId} / {package}。WelcomeActivity(具有 活动):{package} .WelcomeActivity @ b78f4df
onNewIntent:意图{act = android.intent.action.VIEW cat = [android.intent.category.BROWSABLE] dat = https:// {depp_link} ... flg = 0x1001c000 cmp = {applicationId} / {package}。WelcomeActivity(具有 活动):{package} .WelcomeActivity @ b78f4df
onCreate:意图{act = android.intent.action.VIEW cat = [android.intent.category.BROWSABLE] dat = https:// {depp_link} ... flg = 0x1001c000 cmp = {applicationId} / {package}。WelcomeActivity(具有 {package} .WelcomeActivity @ dfe87b2
更新:
1-似乎启动模式与此问题无关。我注意到默认启动模式也是如此。
2- navController.navigate(intent.dataString.toUri())似乎工作正常。所以我想问题出在navController.handleDeepLink(intent)。
答案 0 :(得分:2)
通过测试不同的更改,我得出的结论是“ navController.handleDeepLink(intent)”正在引起这种奇怪的行为。
这是我尝试过的:
我从导航中删除了deepLink,并且深链接正常工作(我已经手动添加了deepLink),并且具有正常的行为:使用singleTask,如果已经创建了活动,则onNewIntent仅被调用一次。如果未创建活动,则调用onCreate。
与此有关的另一个问题是,将在onCreate中自动调用navController.handleDeepLink(intent)(可以在javadocs中进行检查)。调用onNewIntent时,您需要调用navController.handleDeepLink(intent)。
我决定尝试使用NavController中的“ navigate(Uri deepLink)”,并且看到它按预期方式工作(第一段中描述的行为)。 有了这种替代方法,我决定进行一些更改:
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中注意以下代码块很重要:
val data = intent.data
intent.data = null
之所以这样,是因为如果我需要防止调用“ navController.handleDeepLink(intent)”,因为如果存在该信息,它将被自动调用,从而导致异常行为。
navController.graph.hasDeepLink(uri)将帮助您查看图形是否可以处理该uri。如果不使用它,则“ navigate(Uri deepLink)”将引发异常。
如果您遇到相同的问题,希望它可以为您提供帮助。如果您对此有更多了解,请随时发表评论。
答案 1 :(得分:1)
单击隐式深层链接时,FLAG_ACTIVITY_NEW_TASK
的设置是有意的。并且根据文档,将重新创建堆栈,使其处于良好状态。请参见Implicit deep link这里的文档。
如果您不希望这种行为,并且不想更改意图标志,则可以自己处理深层链接,而不用将其传递给导航组件。因此,如果您使用的是AdvancedNavigationSample,则需要删除handledeeplink
并按findNavController().navigate()
进行操作。
还请记住将启动器活动的启动模式设置为singleTask
,以接收有关单击Deepink或通知的新意图。
NavController.handledeeplink()
替换为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)
}
}
}
}
intent.data
存储在变量中,并将其设置为null,以使导航组件无法处理它。也可以在onHandleNewIntent
完整的解决方案在此sample上实现。
优点:
intent.data
中。答案 2 :(得分:1)
在onNewIntent
上的回调首次到达时,只需设置标志intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
并将变异的意图传递给handleDeepLink(intent);
此标志消除了onNewIntent
回调的第二次到达,因为它重新连接到现有的Activity
(通过将堆栈跟踪完全重建到所需的深层链接目标),而不是启动新的Activity
。
详细信息位于handleDeepLink
方法的源代码中。
答案 3 :(得分:0)
这感觉很奇怪,但实际上似乎按预期工作。 The documentation关于隐式深层链接说:
触发隐式深层链接时,后退堆栈的状态取决于是否使用Intent.FLAG_ACTIVITY_NEW_TASK标志启动了隐式Intent:
如果设置了该标志,则清除任务后退堆栈并替换为深层链接目标...。
如果未设置该标志,则将保留在先前应用程序的任务堆栈上,在该任务堆栈上触发了隐式深层链接。
对于您来说,我相信当您点击链接时,意图已经设置了标志Intent.FLAG_ACTIVITY_NEW_TASK
,因此将创建整个新堆栈。当前the implementation只是使用新创建的堆栈重新启动活动,以确保任务状态一致。
如果您不需要这种行为,一种可能的解决方法是在导航组件有机会处理之前,从意图中清除标志Intent.FLAG_ACTIVITY_NEW_TASK
。
答案 4 :(得分:0)
我遇到了类似的问题,我关注的是BottomNavigationView
中有多个NavHostFragment
的{{3}}。因此,将我的补丁发布给那些案件相同的人。
更具体地说,通过通知深层链接启动应用程序时,我的MainActivity的onCreate()
被调用了两次。
我为意图设置了以下标志:
private fun getPendingIntent(data: Uri?): PendingIntent {
val intent = Intent(context, MainActivity::class.java)
intent.action = Intent.ACTION_VIEW
intent.data = data
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)
}
我在MainActivity的清单中没有android:launchMode="singleTask"
,因为它对我的情况没有帮助。
我已经解决了我的问题,首先使用以下代码(感谢您)阻止了navController.handleDeepLink(intent)
在MainActivity的onCreate()
上被自动调用:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val uri = intent.data
intent.data = null
}
,然后在NavigationExtensions
文件中的NavigationAdvancedSample中进行更改,该文件基本上将navController.handleDeepLink(intent)
替换为navController.navigate(uri)
,这导致活动被创建为两次,如您在您的注释中所述帖子。
因此,使用BottomNavigationView
设置导航的代码在MainActivity中如下所示:
private fun setupBottomNavigation(uri: Uri?) {
val navGraphIds =
listOf(
R.navigation.all_integrations,
R.navigation.favourites,
R.navigation.settings
)
currentNavController = bottomNavView.setupWithNavController(
navGraphIds,
supportFragmentManager,
R.id.navHostContainer
)
uri?.let {
bottomNavView.handleDeepLinks(
navGraphIds,
supportFragmentManager,
R.id.navHostContainer,
it
)
}
}