最近のgoogleのサンプルでContainerクラスを作ってそこでRepositoryのインスタンスを作成し、ApplicationクラスでContainerのインスタンスを作成してViewでViewModelにRepositoryを渡す実装がいくつかありました
手動による依存関係挿入でコンテナを使用した依存関係の管理ってやつですね
https://developer.android.com/training/dependency-injection/manual?hl=ja#dependencies-container
気がついてなかったのですがandroidx.lifecycle:lifecycle-*:2.5.0で以下の機能が追加されていました
lifecycle-viewmodel-compose
がラムダ ファクトリを受け取るviewModel()
API を提供するようになりました。これにより、カスタムのViewModelProvider.Factory
を作成せずに、ViewModel
インスタンスを作成できるようになります。
というわけでシンプルな構成のViewModelの実装をしてみます
この構成だとApplicationクラスやContextをRepositoryで使いたい場合でもコンテナで吸収できるのでViewModelをAndroidViewModelにする必要がなくなるのが利点です
※ 推奨事項でAndroidViewModelを使用が非推奨になってました…
AndroidViewModel ではなく ViewModel クラスを使用します。Application クラスは ViewModel で使用しないようにします。代わりに、依存関係を UI またはデータレイヤに移行します。
Project Structureでandroidx.lifecycle:lifecycle-viewmodel-composeの2.5.0以上をimplementationします(現時点で安定版は2.6.1で2.7.0-alpha01が最新です)
確認用に適当なデータを実装します
data class Item(
val id: Int = 0,
val name: String,
)
class UserItems {
companion object {
val items = listOf<Item>(
Item(0, "item 0"),
Item(1, "item 1"),
Item(2, "item 2"),
Item(3, "item 3"),
Item(4, "item 4"),
)
}
}
データを取得するRepositoryを実装
interface ItemsRepository {
fun getAll(): List<Item>
}
class UserItemsRepository : ItemsRepository {
override fun getAll(): List<Item> = UserItems.items
}
ViewModelも実装していきます
class ItemsViewModel(
private val repo: ItemsRepository,
) : ViewModel() {
val items = repo.getAll()
}
Repositoryのインスタンスを作成するコンテナを実装
interface AppContainer {
val itemsRepository: ItemsRepository
}
class AppDataContainer() : AppContainer {
override val itemsRepository: ItemsRepository by lazy {
UserItemsRepository()
}
}
Applicationクラスを実装してコンテナのインスタンスを作成
/**
* ```AndroidManifest.xml
* <application
* android:name=".Application"
* ```
*/
class Application: android.app.Application() {
lateinit var container: AppContainer
override fun onCreate() {
super.onCreate()
container = AppDataContainer()
}
}
画面をdeveloperの説明を参考に実装
@Composable
fun ItemScreen(
itemsViewModel: ItemsViewModel = viewModel {
val application = checkNotNull(get(ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY) as Application)
ItemsViewModel(application.container.itemsRepository)
}
) {
LazyColumn(Modifier.fillMaxSize()) {
itemsIndexed(itemsViewModel.items) { index, item ->
ListItem(headlineContent = { Text("${item.id}: ${item.name}") },)
}
}
}
Android Studio Giraffe 2022.3.1 built on June 29, 2023