Iba*_*ola 14 android mvvm viewmodel kotlin kodein
我们一直在讨论这个问题,但是我们不知道创建视图模型工厂来创建视图模型而不是直接实例化视图模型的原因。创建仅创建视图模型的工厂有什么好处?
我只是举了一个简单的示例,说明我没有工厂如何做到这一点
这是kodein模块:
val heroesRepositoryModel = Kodein {
bind<HeroesRepository>() with singleton {
HeroesRepository()
}
bind<ApiDataSource>() with singleton {
DataModule.create()
}
bind<MainViewModel>() with provider {
MainViewModel()
}
}
Run Code Online (Sandbox Code Playgroud)
我不使用工厂实例化viewmodel的Activity部分
class MainActivity : AppCompatActivity() {
private lateinit var heroesAdapter: HeroAdapter
private lateinit var viewModel: MainViewModel
private val heroesList = mutableListOf<Heroes.MapHero>()
private var page = 0
private var progressBarUpdated = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProviders.of(this)
.get(MainViewModel::class.java)
initAdapter()
initObserver()
findHeroes()
}
Run Code Online (Sandbox Code Playgroud)
我直接实例化用例的ViewModel,而无需在构造函数中使用它
class MainViewModel : ViewModel(), CoroutineScope {
private val heroesRepository: HeroesRepository = heroesRepositoryModel.instance()
val data = MutableLiveData<List<Heroes.MapHero>>()
private var job: Job = Job()
override val coroutineContext: CoroutineContext
get() = uiContext + job
fun getHeroesFromRepository(page: Int) {
launch {
try {
val response = heroesRepository.getHeroes(page).await()
data.value = response.data.results.map { it.convertToMapHero() }
} catch (e: HttpException) {
data.value = null
} catch (e: Throwable) {
data.value = null
}
}
}
override fun onCleared() {
super.onCleared()
job.cancel()
}
}
Run Code Online (Sandbox Code Playgroud)
所以这里有一个使用工厂的例子
class ListFragment : Fragment(), KodeinAware, ContactsAdapter.OnContactListener {
override val kodein by closestKodein()
private lateinit var adapterContacts: ContactsAdapter
private val mainViewModelFactory: MainViewModelFactory by instance()
private val mainViewModel: MainViewModel by lazy {
activity?.run {
ViewModelProviders.of(this, mainViewModelFactory)
.get(MainViewModel::class.java)
} ?: throw Exception("Invalid Activity")
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_list, container, false)
}
Run Code Online (Sandbox Code Playgroud)
viewmodelfactory:
class MainViewModelFactory (private val getContacts: GetContacts) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
return MainViewModel(getContacts) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
Run Code Online (Sandbox Code Playgroud)
和视图模型:
class MainViewModel(private val getContacts: GetContacts) : BaseViewModel() {
lateinit var gamesList: LiveData<PagedList<Contact>>
var contactsSelectedData: MutableLiveData<List<Contact>> = MutableLiveData()
var contactsSelected: ArrayList<Contact> = ArrayList()
private val pagedListConfig by lazy {
PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setInitialLoadSizeHint(PAGES_CONTACTS_SIZE)
.setPageSize(PAGES_CONTACTS_SIZE)
.setPrefetchDistance(PAGES_CONTACTS_SIZE*2)
.build()
}
Run Code Online (Sandbox Code Playgroud)
这是完整的第一个示例:
https://github.com/ibanarriolaIT/Marvel/tree/mvvm
以及完整的第二个示例:
San*_*Sur 24
简而言之,
如果我们需要通过一些input data
对 constructor
的viewModel
,我们需要创建一个factory class
用于视图模型。
例如:-
class MyViewModelFactory constructor(private val repository: DataRepository): ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return if (modelClass.isAssignableFrom(MyViewModel::class.java!!)) {
MyViewModel(this.repository) as T
} else {
throw IllegalArgumentException("ViewModel Not Found")
}
}
}
Run Code Online (Sandbox Code Playgroud)
原因
我们不能直接创建 的对象,ViewModel
因为它不会意识到lifecyclerOwner
。所以我们使用:-
ViewModelProviders.of(this, MyViewModelFactory(repository)).get(MyViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)
Vis*_*ora 13
我们不能自行创建ViewModel。我们需要Android提供的ViewModelProviders实用程序来创建ViewModels。
但是ViewModelProviders只能实例化没有arg构造函数的ViewModels。
因此,如果我有一个带有多个参数的ViewModel,则需要使用一个Factory,可以将其传递给ViewModelProviders,以便在需要MyViewModel实例时使用。
例如 -
public class MyViewModel extends ViewModel {
private final MyRepo myrepo;
public MyViewModel(MyRepo myrepo) {
this.myrepo = myrepo;
}
}
Run Code Online (Sandbox Code Playgroud)
要实例化此ViewModel,我需要有一个工厂,ViewModelProviders可以使用该工厂来创建其实例。
ViewModelProviders实用程序无法使用参数构造函数创建ViewModel的实例,因为它不知道如何以及在构造函数中传递哪些对象。
小智 11
当我们只是使用ViewModel时,我们无法将参数传递给该 ViewModel
class GameViewModel() : ViewModel() {
init {
Log.d(TAG, "GameViewModel created")
}
}
Run Code Online (Sandbox Code Playgroud)
然而,在某些情况下,我们需要将自己的参数传递给 ViewModel。这可以使用ViewModelFactory来完成。
class ScoreViewModel(finalScore: Int) : ViewModel() {
val score = finalScore
init {
Log.d(TAG, "Final score: $finalScore")
}
}
Run Code Online (Sandbox Code Playgroud)
为了实例化这个 ViewModel,我们需要一个ViewModelProvider.Factory,因为简单的 ViewModel 无法实例化它。
class ScoreViewModelFactory(private val finalScore: Int) : ViewModelProvider.Factory {
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")
}
}
Run Code Online (Sandbox Code Playgroud)
当涉及到使用 ViewModelProvider 实例化此 ViewModel 的对象时,我们将 ViewModelFactory 作为参数传递,其中包含有关我们想要传递的自定义参数的信息。它是这样的:
viewModelFactory = ScoreViewModelFactory(score)
viewModel = ViewModelProvider(this,viewModelFactory).get(ScoreViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)
这就是工厂方法存在的原因。
我们一直在讨论这个问题,但是我们不知道创建视图模型工厂来创建视图模型而不是直接实例化视图模型的原因。创建仅创建视图模型的工厂有什么好处?
因为Android只会为尚未为特定给定LifecycleOwner创建的新实例提供给您。
我们也不要忘记ViewModels在配置更改后保持活动状态,因此,如果旋转手机,则不应创建新的ViewModel。
如果您要返回上一个活动,然后重新打开该活动,则应收到先前的ViewModel onCleared()
,而新的活动应具有一个新的ViewModel。
除非您自己这样做,否则您应该只相信ViewModelProviders.Factory
可以完成其工作。
(并且您需要工厂,因为您通常不仅仅具有no-arg
构造函数,您的ViewModel具有构造函数参数,并且ViewModelProvider
在使用非默认构造函数时必须知道如何填写构造函数参数)。
归档时间: |
|
查看次数: |
4107 次 |
最近记录: |