【问题标题】:How to pass runtime arguments to a viewmodel?如何将运行时参数传递给视图模型?
【发布时间】:2021-10-15 13:35:01
【问题描述】:

我有一个看起来像这样的视图模型:

 class FilterByCategoryViewModel @ViewModelInject constructor(
    private val dataManager: AppDataManager,
    private val networkHelper: NetworkHelper,
    private val category: String
) : ViewModel() { ...
 }

我将从ApplicationModule 获得dataManagernetworkHelper。但我需要将category 作为运行时参数传递。我尝试了以下方法,但出现错误无法解析AssistedModule

https://stackoverflow.com/a/65375442/5742365

我也尝试过创建如下视图模型工厂:

val factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory() {
                @NonNull
                override fun <T : ViewModel?> create(@NonNull modelClass: Class<T>): T {
                    return FilterByCategoryViewModel(
                        category
                    ) as T
                }
            }
filterByCategoryViewModel = ViewModelProvider(requireActivity(), factory).get(FilterByCategoryViewModel::class.java)
        

但后来我不得不编辑视图模型以在构造函数中包含 category 参数,并使用字段注入注入 networkHelperdataManager 参数(我不确定它是否以这种方式工作)。但它仍然没有工作。 Viewmodel 现在如下所示:

    class FilterByCategoryViewModel @ViewModelInject constructor(
        private val category: String
    ) : ViewModel() {
        @Inject
        lateinit var dataManager: AppDataManager
        @Inject
        lateinit var networkHelper: NetworkHelper
...
}

现在我在运行应用程序时收到此构建错误:

D:\Workspace\AndroidProjects\RecipeApp\app\build\tmp\kapt3\stubs\debug\com\neeraja\recipeapp\ui\viewmodel\FilterByCategoryViewModel.java:20: error: incompatible types: NonExistentClass cannot be converted to Annotation
    @error.NonExistentClass()
          ^D:\Workspace\AndroidProjects\RecipeApp\app\build\tmp\kapt3\stubs\debug\com\neeraja\recipeapp\ui\viewmodel\FilterByCategoryViewModel.java:34: error: incompatible types: NonExistentClass cannot be converted to Annotation
    @error.NonExistentClass()
          ^
FAILURE: Build completed with 2 failures.

1: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':app:checkDebugDuplicateClasses'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable
   > Duplicate class android.support.v4.app.INotificationSideChannel found in modules core-1.3.2-runtime (androidx.core:core:1.3.2) and support-compat-26.1.0-runtime (com.android.support:support-compat:26.1.0)
     Duplicate class android.support.v4.app.INotificationSideChannel$Stub found in modules core-1.3.2-runtime (androidx.core:core:1.3.2) and support-compat-26.1.0-runtime (com.android.support:support-compat:26.1.0)
     Duplicate class android.support.v4.app.INotificationSideChannel$Stub$Proxy found in modules core-1.3.2-runtime (androidx.core:core:1.3.2) and support-compat-26.1.0-runtime (com.android.support:support-compat:26.1.0)
     Duplicate class android.support.v4.os.IResultReceiver found in modules core-1.3.2-runtime (androidx.core:core:1.3.2) and support-compat-26.1.0-runtime (com.android.support:support-compat:26.1.0)
     Duplicate class android.support.v4.os.IResultReceiver$Stub found in modules core-1.3.2-runtime (androidx.core:core:1.3.2) and support-compat-26.1.0-runtime (com.android.support:support-compat:26.1.0)
     Duplicate class android.support.v4.os.IResultReceiver$Stub$Proxy found in modules core-1.3.2-runtime (androidx.core:core:1.3.2) and support-compat-26.1.0-runtime (com.android.support:support-compat:26.1.0)
     Duplicate class android.support.v4.os.ResultReceiver found in modules core-1.3.2-runtime (androidx.core:core:1.3.2) and support-compat-26.1.0-runtime (com.android.support:support-compat:26.1.0)
     Duplicate class android.support.v4.os.ResultReceiver$1 found in modules core-1.3.2-runtime (androidx.core:core:1.3.2) and support-compat-26.1.0-runtime (com.android.support:support-compat:26.1.0)
     Duplicate class android.support.v4.os.ResultReceiver$MyResultReceiver found in modules core-1.3.2-runtime (androidx.core:core:1.3.2) and support-compat-26.1.0-runtime (com.android.support:support-compat:26.1.0)
     Duplicate class android.support.v4.os.ResultReceiver$MyRunnable found in modules core-1.3.2-runtime (androidx.core:core:1.3.2) and support-compat-26.1.0-runtime (com.android.support:support-compat:26.1.0)
     
     Go to the documentation to learn how to <a href="d.android.com/r/tools/classpath-sync-errors">Fix dependency resolution errors</a>.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
==============================================================================

2: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':app:kaptDebugKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptExecution
   > java.lang.reflect.InvocationTargetException (no error message)

我正在自学 Hilt、MVVM 和 Kotlin,我对此感到非常困惑。对实现这一目标有何建议?

【问题讨论】:

    标签: android kotlin android-mvvm dagger-hilt


    【解决方案1】:

    我不确定刀柄,但我使用 AssistedInject 对 Dagger2 做了同样的事情。 这是我的实现,

    class MyViewModel @AssistedInject constructor(
        @Assisted private val savedStateHandle: SavedStateHandle,
        dataSource: RemoteDataSource 
    ) : ViewModel() {
    
        @AssistedInject.Factory
        interface Factory : AssistedSavedStateViewModelFactory<MyViewModel> {
            override fun create(savedStateHandle: SavedStateHandle): MyViewModel
        }    
        val groupId = savedStateHandle.getLiveData("groupId", "")
        val searchType = savedStateHandle.getLiveData("searchType", 1)
        }
    

    在片段/活动中

    val defArgs = bundleOf("groupId" to groupId, "searchType" to searchType)        
    val factory = viewModelFactory.create(this, defArgs)
    viewModel = ViewModelProvider(this, factory)[MyViewModel::class.java]
    

    【讨论】:

    • 现在我在重建项目时不断收到FilterByCategoryViewModel.Factory cannot be provided without an @Provides-annotated method 错误
    • 我添加了一个模块如下以避免错误:@AssistedModule @Module @InstallIn(SingletonComponent::class) interface AssistedInjectModule {} 现在我不断收到AssistedInjectModule is missing an @InstallIn annotation even though I have kept @InstallIn(SingletonComponent::class)
    【解决方案2】:

    我终于使用 ViewModelProvider.Factory 如下:

    class FilterByTypeViewModelFactory constructor(val dataManager: AppDataManager, 
                                                   val networkHelper: NetworkHelper, 
                                                   val category: String) : ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return FilterByCategoryViewModel(dataManager , networkHelper , category) as T
        }
    }
    

    ViewModel 现在如下所示:

    class FilterByCategoryViewModel @ViewModelInject constructor(
        val dataManager: AppDataManager,
        val networkHelper: NetworkHelper,
        val category: String
    ) : ViewModel() {
    ...
    }
    

    在片段中:

    @AndroidEntryPoint
    class FilterByTypeFragment : Fragment() {
        @Inject lateinit var dataManager: AppDataManager
        @Inject lateinit var networkHelper: NetworkHelper
        ...
         override fun onActivityCreated(savedInstanceState: Bundle?) {
            super.onActivityCreated(savedInstanceState)
            if (arguments != null) {
                category = arguments?.get("categoryId") as String
                val factory = FilterByTypeViewModelFactory(dataManager, networkHelper, category)
                filterByCategoryViewModel = ViewModelProvider(requireActivity(), factory).get(FilterByCategoryViewModel::class.java)
            }
            setupUI()
            setupObserver()
        }
    ...
    }
    

    这对我有用。我刚学过刀柄。我对使用 ViewModelProvider.Factory 或 AssistedInject 等选项感到困惑。虽然这个解决方案对我有用,但我想更多地了解 AssistedInject 以及我们需要选择其中一个的情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-10
      • 2018-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-09
      相关资源
      最近更新 更多