これについては議論してきましたが、viewmodelを直接インスタンス化するのではなく、viewmodelファクトリを作成してviewmodelを作成する理由はわかりません。ビューモデルを作成するだけのファクトリを作成する利点は何ですか?
Factoryを使用せずにそれを実行した簡単な例を示します
ここにkodeinモジュールがあります:
val heroesRepositoryModel = Kodein {
bind<HeroesRepository>() with singleton {
HeroesRepository()
}
bind<ApiDataSource>() with singleton {
DataModule.create()
}
bind<MainViewModel>() with provider {
MainViewModel()
}
}
ファクトリを使用せずにビューモデルをインスタンス化するアクティビティの一部
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()
}
コンストラクターに使用せずにユースケースを直接インスタンス化する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()
}
}
だからここでファクトリを使用した例
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)
}
ビューモデルファクトリ:
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")
}
}
そしてviewmodel:
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()
}
これが完全な最初の例です:
https://github.com/ibanarriolaIT/Marvel/tree/mvvm
そして完全な2番目の例:
自分でViewModelを作成することはできません。 ViewModelを作成するには、Androidによって提供されるViewModelProvidersユーティリティが必要です。
ただし、ViewModelProvidersがインスタンス化できるのは、引数コンストラクタのないViewModelだけです。
したがって、複数の引数を持つViewModelがある場合、MyViewModelのインスタンスが必要なときに使用するViewModelProvidersに渡すことができるファクトリを使用する必要があります。
例えば -
public class MyViewModel extends ViewModel {
private final MyRepo myrepo;
public MyViewModel(MyRepo myrepo) {
this.myrepo = myrepo;
}
}
このViewModelをインスタンス化するには、ViewModelProvidersがインスタンスを作成するために使用できるファクトリが必要です。
ViewModelProvidersユーティリティは、コンストラクターで渡すオブジェクトと方法を知らないため、引数コンストラクターを持つViewModelのインスタンスを作成できません。
これについては議論してきましたが、viewmodelを直接インスタンス化するのではなく、viewmodelファクトリを作成してviewmodelを作成する理由はわかりません。ビューモデルを作成するだけのファクトリを作成する利点は何ですか?
なぜなら、Androidは、まだ作成されていない場合にのみ新しいインスタンスを提供しますその特定の指定されたLifecycleOwnerの場合。
また、ViewModelが構成の変更後も維持されることを忘れないでください。そのため、電話を回転させる場合、新しいViewModelを作成する必要はありません。
前のアクティビティに戻ってこのアクティビティを再び開くと、前のViewModelはonCleared()
を受け取り、新しいアクティビティは新しいViewModelを持つはずです。
あなたが自分でそれをしているのでない限り、あなたはおそらくViewModelProviders.Factory
その仕事をします。
(通常、no-arg
コンストラクター、ViewModelにはコンストラクター引数があり、ViewModelProvider
はデフォルト以外のコンストラクターを使用している場合にコンストラクター引数を入力する方法を知っている必要があります)。
要するに、
passinput data
をconstructor
のviewModel
に渡す必要がある場合は、 a factory class
for viewModel。
例のように:-
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")
}
}
}
理由
ViewModelのオブジェクトを直接作成することはできませんできませんlifecyclerOwner
に注意してください。したがって、次のように使用します。
ViewModelProviders.of(this, MyViewModelFactory(repository)).get(MyViewModel::class.Java)