ViewModelExt.kt
- @Composable
- inline fun <reified VM : ViewModel> assistedViewModel(
- viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
- "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
- },
- crossinline viewModelProducer: (SavedStateHandle) -> VM
- ): VM {
- val factory = if (viewModelStoreOwner is NavBackStackEntry) {
- object : AbstractSavedStateViewModelFactory(viewModelStoreOwner, viewModelStoreOwner.arguments) {
- @Suppress("UNCHECKED_CAST")
- override fun <T : ViewModel?> create(key: String, modelClass: Class<T>, handle: SavedStateHandle): T {
- return viewModelProducer(handle) as T
- }
- }
- } else {
- // Use the default factory provided by the ViewModelStoreOwner
- // and assume it is an @AndroidEntryPoint annotated fragment or activity
- null
- }
- return viewModel(viewModelStoreOwner, factory = factory)
- }
- fun Context.extractActivity(): Activity {
- var ctx = this
- while (ctx is ContextWrapper) {
- if (ctx is Activity) {
- return ctx
- }
- ctx = ctx.baseContext
- }
- throw IllegalStateException(
- "Expected an activity context for creating a HiltViewModelFactory for a " +
- "NavBackStackEntry but instead found: $ctx"
- )
- }
- @HiltAndroidApp
- class MyApplication : Application()
- @AndroidEntryPoint
- class MainActivity : ComponentActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContent {
- MaterialTheme {
- Surface(color = MaterialTheme.colors.background) {
- MyApp()
- }
- }
- }
- }
- }
- @Composable
- fun MyApp() {
- val navController = rememberNavController()
- NavHost(navController, startDestination = "Screen1") {
- composable("Screen1") {
- LazyColumn(modifier = Modifier.fillMaxSize()) {
- items(20) {
- Text(
- text = "Item : $it",
- modifier = Modifier
- .fillMaxWidth()
- .clickable {
- navController.navigate("Screen2/$it")
- }
- .padding(16.dp)
- )
- }
- }
- }
- composable(
- route = "Screen2/{id}",
- arguments = listOf(
- navArgument("id") { type = NavType.IntType },
- )
- ) {
- val arguments = requireNotNull(it.arguments)
- val id = arguments.getInt("id")
- val viewModel = assistedViewModel { savedStateHandle ->
- Screen2ViewModel.provideFactory(LocalContext.current)
- .create(savedStateHandle, id)
- }
- Screen2(viewModel)
- }
- }
- }
- @Composable
- fun Screen2(viewModel: Screen2ViewModel) {
- Text(
- text = viewModel.greet(),
- modifier = Modifier.padding(24.dp)
- )
- }
- class Screen2ViewModel @AssistedInject constructor(
- private val nameProvider: NameProvider,
- @Assisted private val savedStateHandle: SavedStateHandle,
- @Assisted private val id: Int
- ) : ViewModel() {
- @AssistedFactory
- interface Factory {
- fun create(savedStateHandle: SavedStateHandle, id: Int): Screen2ViewModel
- }
- @EntryPoint
- @InstallIn(ActivityComponent::class)
- interface ActivityCreatorEntryPoint {
- fun getScreen2ViewModelFactory(): Factory
- }
- companion object {
- fun provideFactory(context: Context): Factory {
- val activity = context.extractActivity()
- return EntryPoints.get(activity, ActivityCreatorEntryPoint::class.java)
- .getScreen2ViewModelFactory()
- }
- }
- fun greet(): String {
- return "Hello ${nameProvider.name()} : id = $id"
- }
- }
- @Singleton
- class NameProvider @Inject constructor() {
- fun name(): String {
- return "Android"
- }
- }
0 件のコメント:
コメントを投稿