Search code examples
androidandroid-architecture-componentsandroid-viewmodelandroid-architecture-lifecycle

Android ViewModel design/architecture


I'm an android beginner, and just looking for some advice with regard to app architecture - specifically relating to using ViewModels. There is no local database, each screen issues a new network request. I'll look to implement room or something similar later.

Main Activity (Movie List)

I have an activity with a 100% size recycle view showing a list of movies, each movie in the recyclerview has a cover image that the user can touch on to be navigated to a player view. The MainActivity (and it's recycler view) is backed by a ViewModel. The Movie object (wrapped by LiveData) has things you'd expect, like title, category, cover image, url to the mp4 file.

private val movies = MutableLiveData<List<Movie>>()

To transition to PlayerActivity, the intent passes the ID of the selected movie as a string extra.

PlayerActivity

When a movie cell in the recycler view of the MainActivity is selected, I create a new intent to transition to the PlayerActivity where the movie is played. There is an imageView with the movie cover image displayed here too. This view is also backed by a ViewModel.

private val selectedMovie = MutableLiveData<Movie>()

In OnCreate() I get the movie_id string extra from the intent, and create the ViewModel (and the ViewModel does a network request using the movie_id). This view also has a button that, when touched, transitions the user to a ScreenshotActivity. The intent to transition to the ScreenshotActivity also passes the movie_id as a string extra.

ScreenshotActivity

Has a recyclerview of screenshots for the movie displayed, and when touched, a network request is sent back to the server to update the cover image of the movie with one of those screenshots. This activity takes the movie_id extra from the PlayerActivity intent to setup the view.

Questions

  1. It's obviously pretty wasteful to do a network request each time, and I understand I should probably use something like room to cache this information locally. In the absense of a local database, is there a better way to do what I'm doing above with ViewModels? Perhaps a single viewmodel that can be accessed by all of the 3 activities above? In doing so, changes could be made directly to the movie object and syncd across all views? Any good examples on how to do this?
  2. Given my current 3x ViewModels for 3x Activities, how can I notify the MainActivity to update the screenshot, and the PlayerActivity to update the coverimage (on the player) when a screenshot is updated in the ScreenshotActivity?

Solution

  • It's obviously pretty wasteful to do a network request each time, and I understand I should probably use something like room to cache this information locally.

    Well it just depends on the size of your network requests. Are they several megabytes? Then yes, I would cache some of the images of the movie locally.

    In the absense of a local database, is there a better way to do what I'm doing above with ViewModels? Perhaps a single viewmodel that can be accessed by all of the 3 activities above?

    Well, I think that your current approach is not that bad at all, I think we should take a look at the API. In your MovieList your get all data of the movies right? I think at that moment you should minify the data sent by the API. Then when selecting only one movie, download the content such as screenshots and cache it locally. If you can't edit the API, then yes, I would suggest you to download all the content you need and reuse that as much as possible.

    Since your data is already in private val movies = MutableLiveData<List<Movie>>(), why wouldn't you just pass the selected Movie to the PlayerActivity?

    Also note that I would not recommend you to use the same ViewModel for several Activities. Each Activity depends on it's own.

    In doing so, changes could be made directly to the movie object and syncd across all views? Any good examples on how to do this?

    Well the app Telegram has some nice ObserverPattern, I use it a lot in my apps. See this class: NotificationCenter.java. This allows an Activity to subscribe to events. If another method calls an event all subscribers gets triggered. This can help you to 'notify' activities to do some work. You can browse the repository to see how you can use it.

    Basically, when you want to listen for events in your Activity, you need to implement NotificationCenter.NotificationCenterDelegate. Then override didReceivedNotification(int id, Object... args), and (un) subscribe for events like this:

    NotificationCenter.getInstance().addObserver(this, NotificationCenter.scheduleReload);
    

    Then you can notify the subscribed Activities anywhere by calling:

    NotificationCenter.getInstance().postNotificationName(NotificationCenter.scheduleReload);