我正在应用程序中使用捷联导航作为导航解决方案。
当使用生成的安全args而不是深度链接策略时,我面临着不一致的行为。
假设我有以下导航图:
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
app:startDestination="@+id/home_dest">
<fragment
android:id="@+id/home_dest"
android:name="com.example.android.codelabs.navigation.HomeFragment"
android:label="@string/home"
tools:layout="@layout/home_fragment" >
<action
android:id="@+id/action_home_dest_to_deeplink_dest"
app:destination="@id/deeplink_dest" />
</fragment>
<fragment
android:id="@+id/deeplink_dest"
android:name="com.example.android.codelabs.navigation.DeepLinkFragment"
android:label="@string/deeplink"
tools:layout="@layout/deeplink_fragment">
<argument
android:name="myarg"
app:argType="string" />
<deepLink app:uri="example://my-deelink-frag?myArg={myarg}" />
</fragment>
</navigation>我定义了两种导航到DeepLinkFragment的方法
action_home_dest_to_deeplink_dest的导航操作example://my-deelink-frag?myArg={myarg}在DeepLinkFragment中,我使用navArgs()函数来反序列化传入的Bundle,并显示一个简单的Toast消息。
class DeepLinkFragment : Fragment() {
private val args : DeepLinkFragmentArgs by navArgs()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Toast.makeText(requireContext(), args.myarg, Toast.LENGTH_SHORT).show()
}
}在使用生成的安全args导航时,我可以发送一个空字符串作为myArg的值。没问题。
findNavController().navigate(HomeFragmentDirections.actionHomeDestToDeeplinkDest(""))但是,当使用空字符串作为参数通过深度链接方式导航时:
val arg = ""
findNavController().navigate("example://my-deelink-frag?myArg=${arg}".toUri())我跟踪到了堆栈轨迹:
Caused by: java.lang.IllegalArgumentException: Required argument "myarg" is missing and does not have an android:defaultValue
at com.example.android.codelabs.navigation.DeepLinkFragmentArgs$Companion.fromBundle(DeepLinkFragmentArgs.kt:29)
at com.example.android.codelabs.navigation.DeepLinkFragmentArgs.fromBundle(Unknown Source:2)
at java.lang.reflect.Method.invoke(Native Method)
at androidx.navigation.NavArgsLazy.getValue(NavArgsLazy.kt:52)
at androidx.navigation.NavArgsLazy.getValue(NavArgsLazy.kt:34)
at com.example.android.codelabs.navigation.DeepLinkFragment.getArgs(DeepLinkFragment.kt:30)
at com.example.android.codelabs.navigation.DeepLinkFragment.onViewCreated(DeepLinkFragment.kt:34)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2987)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:546)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2106)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:233)
at android.app.ActivityThread.main(ActivityThread.java:8068)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978) 它来自生成的DeeplinkFragmentArgs代码。
public data class DeepLinkFragmentArgs(
public val myarg: String = ""
) : NavArgs {
public fun toBundle(): Bundle {
val result = Bundle()
result.putString("myarg", this.myarg)
return result
}
public companion object {
@JvmStatic
public fun fromBundle(bundle: Bundle): DeepLinkFragmentArgs {
bundle.setClassLoader(DeepLinkFragmentArgs::class.java.classLoader)
val __myarg : String?
if (bundle.containsKey("myarg")) {
__myarg = bundle.getString("myarg")
if (__myarg == null) {
throw IllegalArgumentException("Argument \"myarg\" is marked as non-null but was passed a null value.")
}
} else {
__myarg = ""
}
return DeepLinkFragmentArgs(__myarg)
}
}
}查看代码,似乎是一个空字符串使
bundle.getString("myarg")返回null而不是空字符串?!
作为一个修正,我可以添加android:defaultValue。
然而,我不认为是正确的解决办法。
<argument
android:name="myarg"
android:defaultValue=""
app:argType="string" />在使用deeplinks时,这是已知的限制吗?
发布于 2022-02-13 18:38:14
不确定这是否完全回答了你的问题,但你所做的一切看起来都是正确的。下面根据我自己的经验,做一些相关的说明。
内部LINKS
我可能会使用SafeArgs进行应用程序内部的导航,或者像在我的这段代码中那样调用findNavController.navigate。就我个人而言,我不太喜欢更多的Android标记。
外部LINKS
如果你希望链接从电子邮件等来源工作,那么深度链接选项是最合适的,但你也需要验证输入。正如您似乎所指出的,一个空的默认值本身可能是不够的。
因此,在使用DeepLinkFragmentArgs之前,我将确保您获得了所需的控件。例如,在过去,我有时会发现,在允许导航进行之前进行验证是有用的--例如在货代活动中首先接收深度链接。这意味着我可以阻止深度链接执行,而Chrome是最顶端的(因为这会导致诸如重新创建主活动之类的问题)。
移动深孔
顺便说一句,我发现gmail等电子邮件客户端可能不允许定制URI方案深度链接,因此我的示例使用Android https应用程序,以防您感兴趣。
发布于 2022-02-13 19:12:10
可能不能将空字符串作为参数传递;对于string,通常会将"@null"作为默认值传递(这也需要一个可空字段);但如果您不想使用任何空值,则最好是字符串"default"。如果某些内容可能看起来不一致,您可能没有在AndroidManifest.xml中引用默认的导航图XML,这仅仅定义了深度链接的入口点。此外,可能需要版本2.5.0-alpha01,以便使用当前的AGP 7.1.1进行构建。没有对错,但是让NavController来处理它是很方便的--与编写代码相比,生成代码是首选的。
至少在普通的HTTP中,%02%03将是一个空的查询-字符串参数(但尚未测试)。
https://stackoverflow.com/questions/70925235
复制相似问题