【问题标题】:What is the best way to handle Android ViewModels in navigation graph scope with a Fragment shared across multiple sub-graphs?使用跨多个子图共享的 Fragment 在导航图范围内处理 Android ViewModel 的最佳方法是什么?
【发布时间】:2021-08-22 23:22:51
【问题描述】:

可以从导航层次结构中的多个子图中使用一个片段是合理的。在这种情况下,如果 Fragment 依赖于父 Fragment 提供的视图模型,则视图模型需要位于根据其父级而更改的子图范围内。

Kotlin 提供了一种方便的方法来获取图形范围的视图模型:

    private val fvm: SoftenerViewModel by navGraphViewModels(R.id.navigation_graph_softener)

但是这在子图 id 中是硬编码的。

解决这种情况的最佳方法是什么?

【问题讨论】:

    标签: android androidx android-viewmodel android-navigation


    【解决方案1】:

    以下是一种方法,但鉴于新的扩展函数还没有在库中,它提出了一个问题,是否有更好的方法?

    通过与 Kotlin 提供的扩展函数直接类比,定义以下扩展:

    /**
     * Derived from [androidx.navigation.navGraphViewModels]
     */
    @MainThread
    inline fun <reified VM : ViewModel> Fragment.navGraphViewModels(
        viewModelArgKey: String,
        noinline factoryProducer: (() -> ViewModelProvider.Factory)? = null
    ): Lazy<VM> {
        val backStackEntry by lazy {
            val id = arguments?.getInt(viewModelArgKey, 0)?:0
            require(id != 0) {"Fragment argument $viewModelArgKey required."}
            findNavController().getBackStackEntry(id)
        }
        val storeProducer: () -> ViewModelStore = {
            backStackEntry.viewModelStore
        }
        return createViewModelLazy(VM::class, storeProducer, {
            factoryProducer?.invoke() ?: backStackEntry.defaultViewModelProviderFactory
        })
    }
    

    这不同之处仅在于参数是一个字符串,而参数的名称是需要给出的。惰性确保片段参数在正确的时间被引用。

    它就像现有的androidx库扩展一样使用:

        private val fvm: SoftenerViewModel by navGraphViewModels("view_model_id")
    

    唯一的要求是导航子图定义了参数:

    <?xml version="1.0" encoding="utf-8"?>
    <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"
        android:id="@+id/mobile_navigation"
        app:startDestination="@+id/navigation_home"
        >
    
        <fragment
            android:id="@+id/navigation_home"
            android:name="com...HomeFragment"
            android:label="@string/title_home"
            tools:layout="@layout/fragment_home"
            />
    
    
        <navigation
            android:id="@+id/navigation_graph_softener"
            android:label="Softener"
            app:startDestination="@id/navigation_softener"
            >
            <fragment
                android:id="@+id/navigation_softener"
                android:name="com.hanafey.android.waterstats.ui.softener.SoftenerFragment"
                android:label="@string/title_softener"
                tools:layout="@layout/fragment_softener"
                />
    
            <fragment
                android:id="@+id/navigation_softener_history"
                android:name="com...SoftenerHistoryFragment"
                android:label="Softener History"
                tools:layout="@layout/fragment_softener_history"
                >
                <argument
                    android:name="view_model_id"
                    app:argType="reference"
                    android:defaultValue="@id/navigation_graph_softener"
                    />
            </fragment>
        </navigation>
    </navigation>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-01
      • 2016-02-12
      相关资源
      最近更新 更多