首页 > 解决方案 > 带刀柄的 android ViewModelFactory

问题描述

我首先尝试 androidViewModelHiltDI

正如我从下面的链接中了解的那样,要使用运行时值初始化 ViewModel,我应该使用ViewModelFactory

使用 ViewModelFactory

//ViewModel
class ScoreViewModel(finalScore: Int) : ViewModel() {
   // The final score
   var score = finalScore
   init {
       Log.i("ScoreViewModel", "Final score is $finalScore")
   }
}

//ViewModelFactory
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
   if (modelClass.isAssignableFrom(ScoreViewModel::class.java)) {
       return ScoreViewModel(finalScore) as T
   }
   throw IllegalArgumentException("Unknown ViewModel class")
}


//Fragment
viewModelFactory = ScoreViewModelFactory(ScoreFragmentArgs.fromBundle(arguments!!).score)

并且要使用带有刀柄的 ViewModel,我应该@ViewModelInject按照以下链接中的说明使用

Hilt 和 Jetpack 集成

//ViewModel
class ExampleViewModel @ViewModelInject constructor(
  private val repository: ExampleRepository,
  @Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {
  ...
}

//Activity / Fragment
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
  private val exampleViewModel: ExampleViewModel by viewModels()
  ...
}

但是怎么HiltViewModelFactory呢?

似乎答案在@Assisted但我不知道如何

如何告诉 hilt 我喜欢将存储库接口注入 ViewModel,同时仍然允许 ViewModelFactory 在运行时使用参数初始化 ViewModel?

标签: androiddagger-hilt

解决方案


由@Elye 提供,下一篇文章很有帮助。我推荐阅读。

通过注入将 Activity Intent 数据传递给 ViewModel

使用 Dagger Hilt 注入 ViewModel

似乎不需要大多数工厂,因为大多数viewmodel初始参数都是从以前的片段中获取的,并且可以通过SavedStateHandle标记为@Assisted 时自动注入来访问

为了设置刀柄,我使用了以下代码实验室教程

在您的 Android 应用程序中使用 Hilt

然后,viewModel仅使用下一个代码自动完成注入

请注意,正如 fabioCollini在这里所指出的,它似乎savedStateHandle也可以通过简单地将参数名称作为键来从安全参数中获取值。事实上,这就是我在以下示例中所做的。ps:为了使安全参数更加“安全”,我确实尝试将其替换为SavedStateHandle希望ItemsFragmentArgs它可以工作但应用程序没有编译。我确实希望它会在未来实施(如果已经实施,请告诉我)

//ItemFragment file
@AndroidEntryPoint
class ItemsFragment : Fragment() {

    private val viewModel: ItemsViewModel by viewModels()

    //use viewModel as you would. No need to initialize.
}

//Module file - if you have any repository, remember to bind it 
//or provide the exact implementation as noted in code-labs
@InstallIn(ApplicationComponent::class)
@Module
abstract class DatabaseModuleBinder {

    @Binds
    abstract fun bindGlistRepository(impl: FirestoreGlistRepository): GlistRepository

}


//ItemsViewModel file - lastly, anotate as follows and take your arguments 
//from savedStateHandle (for safe args, use variable name as key)
class ItemsViewModel @ViewModelInject constructor(private val glistRepo: GlistRepository,
                     @Assisted private val savedStateHandle: SavedStateHandle) : ViewModel() {

    private val glistLiveDate = glistRepo.getGlistLiveData(
        savedStateHandle.get<String>("listId")!!
    )

..
}

希望它可以帮助任何人,如果有任何错误,请告诉我


推荐阅读