Passing dependencies to composables not using any DI framework

47 Views Asked by At

I am working on a compose UI library with multiple screens. The logic for now is driven by one big viewmodel. There are use cases and repositories that are used across screens.

How could I split the big view model into smaller ones?

I am using the compose bottom sheet, so I cannot create more composable routes to use a navigation approach (adding the accompanist library is not an option).

With one big view model I currently do the following to create MainScreenWithBottomSheet:

@Composable
fun EntryLevelComposable(
    someDependency: SomeDependency,
) {
    val context = LocalContext.current
    val navController = rememberNavController()

    val viewModel: BigViewModel = viewModel(
        factory = BigViewFlowViewModelFactory(
            context = context,
            someDependency = someDependency,
            owner = checkNotNull(LocalSavedStateRegistryOwner.current)
        )
    )
 
    NavHost(navController = navController, startDestination = "navigationRoutingRouteSummary") {

        composable(route = "mainScreen") {
           val complexUiState: MainUIState by viewModel.mainUiState.collectAsStateWithLifecycle()
           
           Scaffold { padding ->
              MainScreenWithBottomSheet(
                 state = complexUiState
              )
           }
        }
    }
}

The ViewModel factory now creates repositories, that I would like to reuse somehow:

class BigViewModelFactory(
    private val context: Context,
    private val someDependency: omeDependency,
    private val owner: SavedStateRegistryOwner
) : AbstractSavedStateViewModelFactory(owner, null) {

    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(
        key: String,
        modelClass: Class<T>,
        handle: SavedStateHandle
    ): T {
        val aRepo = ARepositoryImpl(...)
        val bRepo = BRepoImpl()

        return BigViewModel(
            aRepo = aRepo,
            bUseCase = SearchUseCaseImpl(bUseCase),
            aUseCase = bRepo::someFunction,
            someDependency = someDependency,
            onSendClicked = onSendClicked,
            savedStateHandle = handle
        ) as T
    }

Now, in my MainScreenWithBottomSheet I want to create/use different view models. These should all reuse the same instances to e.g. the UserSettingsRepository.

While I could create ViewModel factories for each, where do I create the shared repositories, use cases?

How does one create and pass around depencies in a composables without the use of DI frameworks, such as Koin or Dagger?

Creating all viewmodels top level and passing them around seems like a no-go.

I also tried to wrap my head around how Dagger or Koin solve this, but did not get far.

A promising approach could be passing the repositories, and use cases within a container object inside a composition local around the MainScreenWithoutBottomSheet. Would I by using the concept wrong?

0

There are 0 best solutions below