amir
amir

Reputation: 167

Viewmodels in android using mvvm and jetpackcompose

I'm new to MVVM and trying to create an application.

The app has 4 different parts: Profile (login - edit Profile and etc) Categories (shows cats and subcats) Items (show all items, single item page, search, etc) Favorites (fav lists, add to fav, delete fav)

My questions are, how do i navigate the UI using jetpack compose ? Do i need to have one main activity and a navigator that handles the whole app pages or Do i need to create 4 activities with 4 different view models to switch between ?

Is that ideal to have 4 different repositories and gather them all in one big view model ?

Also how do i manage to view model's life cycle, should they live inside the activity ?

Upvotes: 2

Views: 1493

Answers (2)

tyg
tyg

Reputation: 15888

In Compose apps you usually only have one activity, derived from ComponentActivity. The main purpose of the activity will be to set up the Compose tree with setContent. Your entire UI will be rooted here with nested calls of composable functions. The different parts of your app will all be independent composable functions that must be called here. They are called Screens, although that is just a naming convention.They are just simple composable functions you create.

To provide a means of navigation between those parts, you will usually use a NavHost. That is a built-in composable that will have no content of its own, instead it will host your screens. You can use a controller to switch which screen should be currently displayed. Screens are supposed to be displayed using the full screen size minus what is needed for the navigation bars.

Your screen composables will display each of your parts. They can even contain another NavHost if you need a nested navigation when a screen consist of several sub screens. Usually each screen has its own view model associated with it, but it does not need to be only one. The view model should provide all the data that a sceen should display. If you'll only use one view model or multiple ones, or if you even share a view model with different screens is up to you to decide, but each view model should have a meaningful scope of what data it provides. You should probably start out with one view model per screen and go from there.

Your screens should request an instance of the view models they need. You shouldn't create those yourself, there are compose functions available to do so (namely viewModel()). The easiest way to handle view models is to use a dependency injection framework like Hilt, especially if you need to provide parameters to the view model (then you will use hiltViewModel()). Although created for the first time when a screen needs it, view models have their own lifecycle. View models are not automatically destroyed when your composable leaves the compositon, for example when the user navigates to another screen. This is useful because navigating back to the screen will have the view model provide the previous state. You should let the Android SDK handle the lifecycle of your view models.

The responsibility of the view model is just to transform data so it can be easily displayed by your screen composables (this is the business logic, which you might even delegate to a separate domain layer if too complex). The data itself is retrieved from repositories. It is common that a view model uses multiple repositories (again, easiest way to obtain an instance of a repository is to use Hilt). Each repository should provide easy access to retrieve and manipulate the data it holds. Where view models are more UI oriented in what they do, repositories are data oriented. Their main purpose is to provide an agnostic access to the data sources: In an ideal case you could switch out the data source with anonther implementation and only have to adapt the repository; the view model and your compose UI will see no difference. You will want your repositories to provide data as a Flow (that your view model will transform and only in the UI will be collected). In the best case your data sources already provide flows so there won't be much to do for the repository, but maybe the data source is callback based, then your repository would need to encapsulate that with a flow. Repositories may also implement their own caching behavior. Repositories should usually be singletons, meaning there should only be a single instance of each repository class, all view models that need that repository should share the same instance. This also can be easily enforced by using Hilt.

Google provides various sample projects that you can use to see how they have solved all of this. A good one to start with would be the Sunflower project.

Upvotes: 4

Bob
Bob

Reputation: 2868

For navigation you may use Jetpack Compose Navigation in that define your screens and navigation graph in main activity

You can have a ProfileViewModel, CategoriesViewModel, ItemsViewModel & FavoritesViewModel. All of them should do only task specified to that particular screen.

ViewModels should ideally have a lifecycle tied to their respective UI components. For activities you can create and use the view models scoped to the activity's lifecycle.

Code :

@Composable
fun MyApp() {
    val navController = rememberNavController()

    NavHost(navController, startDestination = "profile") {
        composable("profile") {
            val viewModel: ProfileViewModel = viewModel()
            ProfileScreen(navController, viewModel)
        }
        composable("categories") {
            val viewModel: CategoriesViewModel = viewModel()
            CategoriesScreen(navController, viewModel)
        }
        // Define other screens here
    }
}

class ProfileViewModel : ViewModel() {
    // Profile-related data and logic
}

class CategoriesViewModel : ViewModel() {
    // Categories-related data and logic
}

@Composable
fun ProfileScreen(navController: NavController, viewModel: ProfileViewModel) {
    // Profile screen UI
}

@Composable
fun CategoriesScreen(navController: NavController, viewModel: CategoriesViewModel) {
    // Categories screen UI
}

Link for more information: https://developer.android.com/codelabs/basic-android-kotlin-compose-navigation#0

Upvotes: 1

Related Questions