なぜAndroidではビューモデルファクトリーが必要なのか?
疑問点
これまで議論してきましたが、ビューモデルを直接インスタンス化するのではなく、ビューモデルを作成するファクトリーを作成する理由がわかりません。ビューモデルを作成するだけのファクトリーを作成することの利点は何でしょうか。
ファクトリーなしでやった簡単な例を載せただけです
kodeinのモジュールはこちらです。
val heroesRepositoryModel = Kodein {
bind<HeroesRepository>() with singleton {
HeroesRepository()
}
bind<ApiDataSource>() with singleton {
DataModule.create()
}
bind<MainViewModel>() with provider {
MainViewModel()
}
}
ファクトリーを使わずにビューモデルをインスタンス化する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()
}
使用例をコンストラクタに入れずに直接インスタンス化した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)
}
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")
}
}
そして、ビューモデル。
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番目の例です。
https://github.com/AdrianMeizoso/Payment-App
どのように解決するのですか?
ViewModelを自前で作成することはできません。ViewModelを作成するためには、Androidが提供するViewModelProvidersユーティリティが必要です。
しかし、ViewModelProvidersはargコンストラクタを持たないViewModelsのインスタンス化しかできません。
そのため、複数の引数を持つ ViewModel がある場合、MyViewModel のインスタンスが必要なときに使用するために ViewModelProviders に渡すことができる Factory を使用する必要があります。
例えば
public class MyViewModel extends ViewModel {
private final MyRepo myrepo;
public MyViewModel(MyRepo myrepo) {
this.myrepo = myrepo;
}
}
この ViewModel のインスタンスを生成するために、ViewModelProvider が使用できるファクトリが必要です。
ViewModelProviders Utility は、コンストラクタにどのように、どのようなオブジェクトを渡せばよいのか分からないため、引数付きコンストラクタで ViewModel のインスタンスを作成することができません。
関連
-
[解決済み] Androidのソフトキーボードをプログラムで閉じる/隠すにはどうすればよいですか?
-
[解決済み] Androidでアクティビティ起動時にEditTextにフォーカスが当たらないようにする方法
-
[解決済み] Androidの「コンテキスト」とは何ですか?
-
[解決済み] AndroidでPythonを実行する方法はありますか?
-
[解決済み] AndroidのListViewで画像を遅延ロードする方法
-
[解決済み] EclipseのAndroidプラグインで "Debug certificate expired "エラーが発生する。
-
[解決済み] Androidで画面の大きさをピクセル単位で取得する方法
-
[解決済み】Android UserManager.isUserAGoat()の正しい使用例?)
-
[解決済み] HttpPostによる画像送信
-
[解決済み] RecyclerViewのアイテムに波及効果を追加する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] handler.postDelayed()を停止する。
-
[解決済み] wrap_contentでRelativeLayoutがフルスクリーンになってしまう
-
[解決済み] Android Studio - あいまいなメソッド呼び出し getClass()
-
[解決済み] FloatingActionButtonのサンプルとサポートライブラリ
-
[解決済み] 複数のフィルタを持つBroadcastReceiverか、複数のBroadcastReceiverか?
-
[解決済み] アンドロイドでシェイクを検出するには?
-
[解決済み] Gradleでビルドタイプを使用し、ContentProviderを使用する同じアプリを1つのデバイスで実行する。
-
[解決済み] PendingIntentの "requestCode "は何に使うのですか?
-
[解決済み] FABアイコンの色を設定する
-
[解決済み] HttpURLConnectionを使ったPOSTによるファイル送信