android 带有刀柄的 ViewModelFactory
android ViewModelFactory with hilt
我首先尝试 android ViewModel
和 Hilt
DI
据我了解 link,要在 运行 时使用值初始化 ViewModel,我应该使用 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
,如下所述 link
//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()
...
}
但是如何将 Hilt
与 ViewModelFactory
一起使用?
似乎答案在 @Assisted
中,但我不知道如何
如何告诉 hilt 我喜欢它向 ViewModel 注入存储库接口,同时仍然允许 ViewModelFactory 在 运行 时使用参数初始化 ViewModel?
将您的 ScoreViewModelFactory 传递到 viewModel 的内置 ktx 扩展中。您还可以通过将 SavedStateHandle 本身与 defaultViewModelProviderFactory 一起使用来使用 Activity/Fragment 个参数。
/*
Gradle Dependencies
def lifecycle_version = "2.2.0"
def hiltLifeVersion = "1.0.0-alpha01"
def hiltVersion = "2.28.1-alpha"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "com.google.dagger:hilt-android:$hiltVersion"
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01"
implementation "androidx.hilt:hilt-work:$hiltLifeVersion"
implementation "androidx.hilt:hilt-common:1.0.0-alpha01"
kapt "com.google.dagger:hilt-android-compiler:$hiltVersion"
kapt "androidx.hilt:hilt-compiler:$hiltLifeVersion"
*/
import androidx.fragment.app.viewModels
@AndroidEntryPoint
class ExampleFragment : Fragment(R.layout.example_fragment) {
//internally using defaultViewModelProviderFactory
private val viewModel : ExampleViewModel by viewModels()
//or you own viewmodal factory instance --> scoreViewModelFactory
private val viewModel : ExampleViewModel by viewModels { scoreViewModelFactory }
}
class ExampleViewModel @ViewModelInject constructor(
private val repository: ExampleRepository,
@Assisted override val savedStateHandle: SavedStateHandle
) : ViewModel() {
//bundle args -> String, Int, Parcelable etc..
private val arg1LiveData: MutableLiveData<String> =
savedStateHandle.getLiveData("arg1", "")
}
在片段视图模型的内置 ktx 扩展中
@MainThread
inline fun <reified VM : ViewModel> Fragment.viewModels(
noinline ownerProducer: () -> ViewModelStoreOwner = { this },
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)
感谢@Elye,接下来的文章帮了大忙。我推荐阅读。
Passing Activity Intent Data to ViewModel through Injection
Injecting ViewModel with Dagger Hilt
似乎不需要大部分工厂,因为大多数 viewmodel
初始参数取自先前的片段,可以通过 SavedStateHandle
访问,如果标记为 @Assisted[=21= 则自动注入]
为了设置刀柄,我使用了以下代码实验室教程
Using Hilt in your Android app
然后,viewModel
仅使用下一个代码自动完成注入
请注意,如 fabioCollini here, it seems savedStateHandle
can also get values from safe args 所述,只需将参数名称作为键即可。事实上,这就是我在下面的例子中所做的。 ps:为了让安全参数更“安全”,我确实尝试用 ItemsFragmentArgs
替换 SavedStateHandle
希望它能工作,但应用程序没有编译。我希望它能在未来实现(如果已经实现,请告诉我)
//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")!!
)
..
}
希望对ps任何人有所帮助,如果有任何错误,请告诉我
我首先尝试 android ViewModel
和 Hilt
DI
据我了解 link,要在 运行 时使用值初始化 ViewModel,我应该使用 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
,如下所述 link
//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()
...
}
但是如何将 Hilt
与 ViewModelFactory
一起使用?
似乎答案在 @Assisted
中,但我不知道如何
如何告诉 hilt 我喜欢它向 ViewModel 注入存储库接口,同时仍然允许 ViewModelFactory 在 运行 时使用参数初始化 ViewModel?
将您的 ScoreViewModelFactory 传递到 viewModel 的内置 ktx 扩展中。您还可以通过将 SavedStateHandle 本身与 defaultViewModelProviderFactory 一起使用来使用 Activity/Fragment 个参数。
/*
Gradle Dependencies
def lifecycle_version = "2.2.0"
def hiltLifeVersion = "1.0.0-alpha01"
def hiltVersion = "2.28.1-alpha"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "com.google.dagger:hilt-android:$hiltVersion"
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01"
implementation "androidx.hilt:hilt-work:$hiltLifeVersion"
implementation "androidx.hilt:hilt-common:1.0.0-alpha01"
kapt "com.google.dagger:hilt-android-compiler:$hiltVersion"
kapt "androidx.hilt:hilt-compiler:$hiltLifeVersion"
*/
import androidx.fragment.app.viewModels
@AndroidEntryPoint
class ExampleFragment : Fragment(R.layout.example_fragment) {
//internally using defaultViewModelProviderFactory
private val viewModel : ExampleViewModel by viewModels()
//or you own viewmodal factory instance --> scoreViewModelFactory
private val viewModel : ExampleViewModel by viewModels { scoreViewModelFactory }
}
class ExampleViewModel @ViewModelInject constructor(
private val repository: ExampleRepository,
@Assisted override val savedStateHandle: SavedStateHandle
) : ViewModel() {
//bundle args -> String, Int, Parcelable etc..
private val arg1LiveData: MutableLiveData<String> =
savedStateHandle.getLiveData("arg1", "")
}
在片段视图模型的内置 ktx 扩展中
@MainThread
inline fun <reified VM : ViewModel> Fragment.viewModels(
noinline ownerProducer: () -> ViewModelStoreOwner = { this },
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)
感谢@Elye,接下来的文章帮了大忙。我推荐阅读。
Passing Activity Intent Data to ViewModel through Injection
Injecting ViewModel with Dagger Hilt
似乎不需要大部分工厂,因为大多数 viewmodel
初始参数取自先前的片段,可以通过 SavedStateHandle
访问,如果标记为 @Assisted[=21= 则自动注入]
为了设置刀柄,我使用了以下代码实验室教程
Using Hilt in your Android app
然后,viewModel
仅使用下一个代码自动完成注入
请注意,如 fabioCollini here, it seems savedStateHandle
can also get values from safe args 所述,只需将参数名称作为键即可。事实上,这就是我在下面的例子中所做的。 ps:为了让安全参数更“安全”,我确实尝试用 ItemsFragmentArgs
替换 SavedStateHandle
希望它能工作,但应用程序没有编译。我希望它能在未来实现(如果已经实现,请告诉我)
//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")!!
)
..
}
希望对ps任何人有所帮助,如果有任何错误,请告诉我