4

I have next screen:

@ExperimentalMaterialApi
@Composable
fun AccountListScreen(
    navController: NavController,
    viewModel: AccountListViewModel = hiltViewModel()
) {

And I want to make a preview for this screen.

I'm trying to do this the following way:

@ExperimentalMaterialApi
@Preview(showBackground = true, backgroundColor = 0xFFFFFF, showSystemUi = true)
@Composable
fun AccountListScreenPreview() {
    AccountListScreen(
        navController = rememberNavController(),
        viewModel = hiltViewModel()
    )
}

But unfortunately I get the following error when trying to build a preview:

java.lang.IllegalStateException: ViewModels creation is not supported in Preview

How can this problem be solved? Also here is code of some my classes

Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
Morozov
  • 4,968
  • 6
  • 39
  • 70
  • 1
    Does this answer your question? [How to get preview in composable functions that depend on a view model?](https://stackoverflow.com/questions/69089816/how-to-get-preview-in-composable-functions-that-depend-on-a-view-model) I see your comment under my reply, but I don't understand how this question is different. – Phil Dukhov Oct 05 '21 at 06:38
  • No, I still don't understand how to apply this answer to my case so that I can display my screen. I don't have a callback implemented and I don't think I need it. if you need to provide a little more code, you tell me, because I don't understand how to solve the problem yet.sry – Morozov Oct 05 '21 at 07:43

3 Answers3

1

What I do in my apps is create a wrapper for my root composable that gets the state from the viewmodel and passes that to a 2nd Composable, where I have my actual content. If there are callbacks that the composable needs to call into the viewModel, then I define those as an interface that the viewModel implements. That way my composable, which I want to preview, receives just a State class and, if needed, an interface for the callbacks, which I can easily stub out.

Something like this:

@Composable
fun CityScreen(
    viewModel: CityViewModel,
    modifier: Modifier = Modifier,
) {
    val state = viewModel.state.collectAsState()
    CityScreen(
        state = state.value,
        callbacks = viewModel,
        modifier = modifier,
    )
}

@Composable
private fun CityScreen(
    state: CityState,
    callbacks: CityCallbacks,
    modifier: Modifier = Modifier,
) {
    // code here
}
Francesc
  • 25,014
  • 10
  • 66
  • 84
  • I kind of understood the idea, but unfortunately I can't apply it to my specific case. As I understand it, you are already doing a preview in the second section of the code `CityScreen`. – Morozov Oct 05 '21 at 05:04
0

Depending on what you wanna test with your preview, you can mock view model injections(like showed in this answer) or the view model itself.

To mock the view model you can create an interface of your view model, in this case it should be abstract class to subclass from ViewModel:

abstract class AccountListViewModel: ViewModel() {
    // interface visible to your view
}

@HiltViewModel
class AccountListViewModelImpl: AccountListViewModel() {
   // implementation which works using dependencies
}

And this is how you can use it:

@Composable
fun AccountListScreen(
    navController: NavController,
    viewModel: AccountListViewModel = hiltViewModel<AccountListViewModelImpl>()
) {

}

@Preview(showBackground = true, backgroundColor = 0xFFFFFF, showSystemUi = true)
@Composable
fun AccountListScreenPreview() {
    AccountListScreen(
        navController = rememberNavController(),
        viewModel = object: AccountListViewModel() {
            // implementation with test data
        }
    )
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
0

can't say much about interactive preview, If you are interested in running a preview of your hiltViewModels on an emulator, you can create a custom run configuration for an activity that is marked with @AndroidEntryPoint.

PreviewActivity used by current UI toolkit package doesn't have Hilt support. I have an article explaining its steps with screenshots, check from here

Chetan Gupta
  • 1,477
  • 1
  • 13
  • 22