带刀柄的android ViewModelFactory
我首先尝试安卓带刀柄的android ViewModelFactory,android,dagger-hilt,Android,Dagger Hilt,我首先尝试安卓ViewModel和HiltDI 我从下面的链接中了解到,要在运行时使用值初始化ViewModel,我应该使用ViewModelFactory 但是如何将Hilt与ViewModelFactory一起使用呢 答案似乎在@Assisted中,但我不知道如何找到答案 如何告诉hilt我喜欢将存储库接口注入ViewModel,同时仍然允许ViewModelFactory在运行时使用参数初始化ViewModel?将您的ScoreViewModelFactory传递到ViewModel的内
ViewModel
和Hilt
DI
我从下面的链接中了解到,要在运行时使用值初始化ViewModel,我应该使用ViewModelFactory
但是如何将Hilt
与ViewModelFactory
一起使用呢
答案似乎在@Assisted
中,但我不知道如何找到答案
如何告诉hilt我喜欢将存储库接口注入ViewModel,同时仍然允许ViewModelFactory在运行时使用参数初始化ViewModel?将您的ScoreViewModelFactory传递到ViewModel的内置ktx扩展中。您还可以通过将SavedStateHandle本身与defaultViewModelProviderFactory一起使用活动/片段参数
/*
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", "")
}
/*
梯度依赖
def lifecycle_version=“2.2.0”
def hiltLifeVersion=“1.0.0-alpha01”
def hiltVersion=“2.28.1-alpha”
实现“androidx.lifecycle:lifecycle viewmodel ktx:$lifecycle\u版本”
实现“androidx.lifecycle:lifecycle viewmodel savedstate:$lifecycle_版本”
实现“androidx.lifecycle:lifecycle livedata ktx:$lifecycle\u版本”
实现“com.google.dagger:hiltandroid:$hiltVersion”
实现“androidx.hilt:hilt生命周期视图模型:1.0.0-alpha01”
实现“androidx.hilt:hilt工作:$hiltLifeVersion”
实现“androidx.hilt:hilt common:1.0.0-alpha01”
kapt“com.google.dagger:hilt android编译器:$hilt版本”
kapt“androidx.hilt:hilt编译器:$hiltLifeVersion”
*/
导入androidx.fragment.app.viewModels
@雄蕊识别点
类ExampleFragment:Fragment(R.layout.example\u Fragment){
//在内部使用defaultViewModelProviderFactory
private val viewModel:ExampleViewModel by viewModels()
//或者您拥有viewmodal工厂实例-->scoreViewModelFactory
私有val viewModel:ExampleViewModelByViewModels{scoreViewModelFactory}
}
类ExampleViewModel@ViewModelInject构造函数(
私有val存储库:示例存储库,
@辅助覆盖val savedStateHandle:savedStateHandle
):ViewModel(){
//bundle args->String、Int、Parcelable等。。
private val arg1LiveData:MutableLiveData=
savedStateHandle.getLiveData(“arg1”、“arg1”)
}
Fragment viewmodel的内置ktx扩展
@MainThread
inline fun <reified VM : ViewModel> Fragment.viewModels(
noinline ownerProducer: () -> ViewModelStoreOwner = { this },
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)
@MainThread
inline fun Fragment.viewModels(
noinline ownerProducer:()->ViewModelStoreOwner={this},
noinline factoryProducer:(()->Factory)?=null
)=createViewModelLazy(VM::class,{ownerProducer().viewModelStore},factoryProducer)
由@Elye提供,接下来的文章帮助很大。我推荐一本书
似乎大部分工厂都不需要,因为大部分viewmodel
初始参数都取自前面的片段,可以通过savedstateholder
访问,如果标记为@Assisted,则会自动注入
为了设置hilt,我使用了下面的代码实验室教程
然后,viewModel
注入只使用下一个代码自动完成
请注意,正如Fabiocolini所指出的那样,savedStateHandle
似乎也可以通过简单地将参数名称作为键来获取值。事实上,这就是我在下面的例子中所做的。ps:为了使安全参数更“安全”,我尝试用ItemsFragmentArgs
替换savedstateholder
,希望它能工作,但应用程序没有编译。我真的希望将来能实施(如果已经实施,请告诉我)
//ItemFragment文件
@雄蕊识别点
类ItemsFragment:Fragment(){
private val viewModel:ItemsViewModel by viewModels()
//如您所愿使用viewModel。无需初始化。
}
//模块文件-如果您有任何存储库,请记住绑定它
//或者提供代码实验室中提到的精确实现
@InstallIn(ApplicationComponent::class)
@模块
抽象类数据库ModuleBinder{
@束缚
抽象趣味双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语双语
}
//ItemsViewModel文件-最后,声明如下并接受您的参数
//从savedStateHandle(对于安全参数,使用变量名作为键)
类ItemsViewModel@ViewModelInject构造函数(私有值glistRepo:GlistRepository,
@辅助私有val savedstatehold:savedstatehold):ViewModel(){
private val glistLiveDate=glistRepo.getGlistLiveData(
savedstatehold.get(“listId”)!!
)
..
}
希望它能帮助任何人,如果有任何错误,请让我知道这篇文章可能会提供如何处理此问题的清晰共享我的问题是,我在Fragment中使用了viewmodel,而在Fragment中我没有提到@AndroIdentityPoint。我在活动中提到了这一点,但在片段中没有提到。要在视图模型中使用安全参数,您可以实现我在这里展示的内容:
@ViewModelInject
和@Assisted
现在不推荐使用。
//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")!!
)
..
}
@MainThread
inline fun <reified VM : ViewModel> Fragment.viewModels(
noinline ownerProducer: () -> ViewModelStoreOwner = { this },
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)
//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")!!
)
..
}