android - 深层链接空字符串参数

标签 android android-architecture-navigation

我正在使用 Jetpack Navigation作为我的应用程序中的导航解决方案。
我在使用 generated safe 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 的方法。 :
  • ID 为 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()
        }
    }
    
    使用 generated safe 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)
        }
      }
    }
    

    Looking at the code it seems as if an empty string is making the bundle.getString("myarg") return null instead of the empty string?!


    作为修复,我可以添加 android:defaultValue .
    但是我认为这不是正确的解决方案。
    <argument
        android:name="myarg"
        android:defaultValue=""
        app:argType="string" />
    
    这是使用深度链接时的已知限制吗?

    最佳答案

    不确定这是否完全回答了您的问题,但您所做的一切看起来都是正确的。以下是根据我自己的经验的一些相关说明。
    内部链接
    我可能会使用 SafeArgs 在应用程序内部进行导航,或者直接调用 findNavController.navigatethis code of mine .就我个人而言,我不太喜欢更多的 Android XML 标记。
    外部链接
    如果您希望链接来自电子邮件等来源,那么深度链接选项是最合适的,但您还需要验证输入。正如您似乎指出的那样,一个空的默认值本身可能是不够的。
    因此,在使用 DeepLinkFragmentArgs 之前,我会确保您获得所需的控制。例如,在过去,我有时发现在允许导航继续之前进行验证很有用 - 例如,首先在 Forwarder Activity 中接收深层链接。 .这意味着我可以阻止在 Chrome 自定义选项卡位于最顶层时执行深层链接(因为这会导致诸如重新创建主要 Activity 之类的问题)。
    移动深度链接
    顺便说一句,我发现 gmail 等电子邮件客户端可能不允许自定义 URI 方案深层链接,所以我的示例使用 Android https applinks ,以防万一您对此感兴趣。

    关于android - 深层链接空字符串参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70925235/

    相关文章:

    Android android.view.InflateException 二进制 XML 文件行 #16 : Error inflating class fragment

    android - BroadcastReceiver未接收 Intent

    android - A图表引擎 : Align Y-Axis Labels on right side of Axis itself

    android - 将 Serializable 用作 Android 导航组件的深层链接参数

    android - 自定义 NavController 和自定义 NavHost

    android - 为什么我的 fragment 没有显示在导航 Controller 中?

    kotlin - 如何从 Compose-Navigation 中的返回堆栈中删除可组合项

    android - 从原始文件夹获取随机声音文件-Android-MediaPlayer

    android - 在android中重用膨胀 View

    android - 导航组件 : parcelable argument but get error Type mismatch: inferred type is Student but String was expected