【问题标题】:Android SafeArgs generated action is missing argumentsAndroid SafeArgs 生成的操作缺少参数
【发布时间】:2019-12-30 21:22:58
【问题描述】:

我的项目使用 SafeArgs。我已经切换到其他人创建的分支,并且构建项目会生成编译器错误,因为即使在 nav_graph 中,生成的“~Directions”类方法也会返回 ActionOnlyNavDirections(没有传递给目标片段的参数)接受一个论点。

例如,使用以下 nav_graph.xml:

<fragment
    android:id="@+id/fragment_a"
    android:name="com.myapp.ui.fragment.FragmentA"
    android:label="Fragment A"
    tools:layout="@layout/fragment_a">

<argument
        android:name="userName"
        android:defaultValue=" "
        app:argType="string" />
    <action
        android:id="@+id/action_fragment_a_to_fragmentX"
        app:destination="@id/fragmentX" />

    <action
        android:id="@+id/action_fragment_a_to_homeFragment"
        app:destination="@id/homeFragment" />

    <action
        android:id="@+id/action_fragmentA_to_fragmentC"
        app:destination="@id/fragmentC"
        app:popUpTo="@id/loginFragment" />

</fragment>

<fragment
    android:id="@+id/fragment_b"
    android:name="com.myapp.ui.fragment.FragmentB"
    android:label="Fragment B"
    tools:layout="@layout/fragment_b">

    <argument
        android:name="from"
        app:argType="com.myapp.data.local.model.ToFragmentBFrom"/>

    <action
        android:id="@+id/action_fragmentB_to_homeFragment"
        app:destination="@id/homeFragment" />

    <action
        android:id="@+id/action_fragmentB_to_fragmentC"
        app:destination="@id/fragmentC"
        app:popUpTo="@id/homeFragment" />

</fragment>

<fragment
    android:id="@+id/fragment_c"
    android:name="com.myapp.fragment.fragmentC"
    android:label="Fragment C"
    tools:layout="@layout/fragment_c">

    <argument
        android:name="userName"
        app:argType="string" />
</fragment>

我结束了以下方向类:

class FragmentADirections private constructor() {
    private data class ActionFragmentAToFragmentC(val userName: String) : NavDirections {
        override fun getActionId(): Int = R.id.action_fragmentA_to_fragmentC

        override fun getArguments(): Bundle {
            val result = Bundle()
            result.putString("userName", this.userName)
            return result
        }
    }

    companion object {
        fun actionFragmentAToFragmentX(): NavDirections =
                ActionOnlyNavDirections(R.id.action_fragmentA_to_fragmentX)

        fun actionFragmentAToHomeFragment(): NavDirections =
                ActionOnlyNavDirections(R.id.action_fragmentA_to_homeFragment)

        fun actionFragmentAToFragmentC(userName: String): NavDirections =
                ActionFragmentAToFragmentC(userName)

        fun actionGlobalFragmentA(userName: String = " "): NavDirections =
                NavGraphDirections.actionGlobalFragmentA(userName)


    }
}

和:

class FragmentBDirections private constructor() {
    companion object {
        fun actionFragmentBToHomeFragment(): NavDirections =
                ActionOnlyNavDirections(R.id.action_fragmentA_to_homeFragment)

        fun actionFragmentBToFragmentC(): NavDirections =
                ActionOnlyNavDirections(R.id.action_fragmentB_to_fragmentC)
    }
}

如您所见,FragmentC 采用“userName”参数,而 actionFragmentAToFragmentC 尊重这一点,而 actionFragmentBToFragmentC 则没有。 我尝试过清理、手动删除构建文件夹、使缓存无效并重新启动以及重建,但生成的类仍然看起来一样。为什么 SafeArgs 为一个方向类而不是另一个生成参数?

如何在构建时调试 SafeArgs 插件以详细了解导致此问题的原因?

【问题讨论】:

  • 有什么解决办法吗?
  • 很遗憾,没有。我们必须找到其他方法将信息传递到目标片段

标签: android android-architecture-navigation android-safe-args


【解决方案1】:

这听起来和感觉有点尴尬,因为生成的FragmentBDirections.class 应该自动包含FragmentC 的参数。我有时也会遇到这个问题,但我无法告诉你为什么安全的 args 插件会这样,尤其是为什么它的行为并不总是相似。

要解决此问题,请在 &lt;action&gt; 中显式添加 &lt;argument&gt;

<action
    android:id="@+id/action_fragmentB_to_fragmentC"
    app:destination="@id/fragmentC"
    app:popUpTo="@id/homeFragment" />
    
    <argument
        android:name="userName"
        app:argType="String" />
</action>

当然,这会在 NavGraph 中产生一些代码开销,因为您需要始终在 &lt;fragment&gt;&lt;action&gt; 中指定参数。这似乎不是“最干净”的解决方案。但这对我始终有效,而且我仍然可以从 SafeArgs 中获利。

【讨论】:

    【解决方案2】:

    对我来说,这是因为我的源片段和目标片段在同一个 xml 文件中,但在不同的导航元素下。将两个片段移动到同一个导航元素下会生成参数

    我从这里改变了(使用嵌套导航元素)

    <navigation 
        ...
        android:id="@+id/nav_main">
    
        <fragment
            android:id="@+id/fragment_a"
            android:name="com.myapp.ui.fragment.FragmentA"
            android:label="Fragment A"
            tools:layout="@layout/fragment_a">
            <action
                 android:id="@+id/action_fragment_a_to_fragment_b"
                app:destination="@id/fragment_b" />
        </fragment>
    
        <navigation 
            ...
            android:id="@+id/nav_other">
            <fragment
                android:id="@+id/fragment_b"
                android:name="com.myapp.ui.fragment.FragmentB"
                android:label="Fragment B"
                tools:layout="@layout/fragment_b">
    
                <argument
                    android:name="from"
                    app:argType="com.myapp.data.local.model.ToFragmentBFrom"/>
            </fragment>
        </navigation>
    </navigation>
    

    到这里

    <navigation 
        ...
        android:id="@+id/nav_main">
    
        <fragment
            android:id="@+id/fragment_a"
            android:name="com.myapp.ui.fragment.FragmentA"
            android:label="Fragment A"
            tools:layout="@layout/fragment_a">
            <action
                 android:id="@+id/action_fragment_a_to_fragment_b"
                app:destination="@id/fragment_b" />
        </fragment>
    
        <fragment
            android:id="@+id/fragment_b"
            android:name="com.myapp.ui.fragment.FragmentB"
            android:label="Fragment B"
            tools:layout="@layout/fragment_b">
    
            <argument
                android:name="from"
                app:argType="com.myapp.data.local.model.ToFragmentBFrom"/>
        </fragment>
    </navigation>
    

    在导航元素或整个图表中导航时,您似乎可能需要双重定义参数(在目标和参数中),尽管我在documentation 中没有看到任何具体提及

    【讨论】:

      【解决方案3】:

      我从“safeargs”更改为“safeargs.kotlin”,它起作用了。 尽管Docs 说“safeargs”应该适用于 Java 和 Kotlin。

      plugins {
        // id 'androidx.navigation.safeargs' 
        id 'androidx.navigation.safeargs.kotlin'
      }
      

      【讨论】:

        【解决方案4】:

        默认值在 FragmentA 中定义为

        android:defaultValue=" "
        

        但不在 FragmentB 中。默认情况下,导航组件不知道将什么分配给不可为空的字符串。

        尝试在片段 B 中做同样的事情。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-08-07
          • 2013-06-07
          • 1970-01-01
          • 2012-03-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多