Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reacting to activity lifecycle in ViewModel

Tags:

I'm trying to create an app which will use MVVM architecture and there's one thing I quite don't understand.

Official Android docs say that's not a good idea to reference activity context in ViewModel's (as ViewModel may outlive activity) so I've started to wonder about usecase when I want to execute some action when my activity is resumed.

I know ViewModel's shouldn't do business logic themselves but even if I use some service class (let's say GPSService which has to start and pauseeach time activity is resumed on paused), and inside this service I react to activity onResume (using Lifecycle observer) I will still reference this activity from ViewModel as I'm referencing service which holds reference to activity being observed, this may cause activity leak (correct me if I'm wrong).

So my question is, how to react to activity or fragment lifecycle in MVVM architecture?

like image 867
Androider Avatar asked Sep 29 '18 07:09

Androider


People also ask

Is ViewModel life Cycle Aware?

Lifecycle Awareness :Viewmodel is lifecycle aware. It is automatically cleared when the lifecycle they are observing gets permanently destroyed.

What is the lifecycle of a ViewModel?

ViewModel objects are scoped to the Lifecycle passed to the ViewModelProvider when getting the ViewModel . The ViewModel remains in memory until the Lifecycle it's scoped to goes away permanently: in the case of an activity, when it finishes, while in the case of a fragment, when it's detached.

How does ViewModel survive change configuration?

The ViewModel class allows data to survive configuration changes such as screen rotations. Usually, one of the first things we find out when learning Android development is that activities get re-created after configuration changes. When it happens, we lose all initialized variables and the view gets re-rendered.


2 Answers

If you need to have a ViewModel be lifecycle aware, then you can have it implement LifeCycleObserver and override life cycle events as necessary. Example,

public class MyModel extends ViewModel implements     LifecycleObserver {    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)   protected void onLifeCycleStop() {       // do something   } } 

In the activity or fragment then you can add the view model to the activity life cycle owner.

public class MyActivity extends AppCompatActivity {    protected MyModel mMyModel;    @Override   public void onCreate(Bundle savedInstanceState) {       super.onCreate(savedInstanceState);        mMyModel = ViewModelProviders           .of(this)           .get(MyModel.class);        getLifecycle().addObserver(mMyModel);   } } 
like image 170
farid_z Avatar answered Nov 02 '22 06:11

farid_z


I know ViewModel's shouldn't do business logic themselves

Yes, you're right. ViewModel should not contain business logic but it should contain UI related logic. So basically, API calls or Some location related stuffs should be avoided in ViewModel logic.

So what if you wanna make some scenario which can react to any activity lifecycle? I'll suggest you to use LifecycleObserver.

Why?, Because LifecycleObserver will provide you callbacks once it's LifecycleOwner will change it's state.

What is LifecycleOwner here? In our case it may be Activity/Fragment.


So, how you can achieve this?

Let's say you want to make location requests during resume & pause period of any activity.

So, for that you can create a class called LocationUpdates as LifecycleObserver like below:

class LocationUpdates : LifecycleObserver {  constructor(){     // some basic location related initialization here }  @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) fun connectListener() {     // this method will respond to resume event of our Lifecycle owner (activity/fragment in our case)    // So let's get location here and provide callback }  @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) fun disconnectListener() {     // this method will respond to pause event of our Lifecycle owner (activity/fragment in our case)    // So let's stop receiveing location updates here and remove callback }  @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) // Optional if you want to cleanup references fun cleanUp() {     // this method will respond to destroy event of our Lifecycle owner (activity/fragment in our case)    // Clean up code here } } 

Now from your activity, you can directly make your LocationUpdates, and receive callback.

class MyActivity : AppCompatActivity() {  private lateinit var mLocationUpdates: LocationUpdates  override fun onCreate(savedInstanceState: Bundle?) {     super.onCreate(savedInstanceState)     //Initialize your LifecycleObserver here & assign it to this activity's lifecycle     lifecycle.addObserver(mLocationUpdates) } } 

You can refer to how to handle Lifecycle & Codelabs example.


Edit:

If you want to have ViewModel for that job, consider this:

class MyViewModel : ViewModel { private lateinit var mLocationUpdates: LocationUpdates  constructor() : super() {     // initialize LocationUpdates here }  // Assign our LifecyclerObserver to LifecycleOwner fun addLocationUpdates(lifecycle: Lifecycle){     lifecycle.addObserver(mLocationUpdates) }  //Optional, we really don't need this. fun removeLocationUpdates(lifecycle: Lifecycle){     lifecycle.removeObserver(mLocationUpdates) } } 

If your LocationUpdates depends upon Context, consider using AndroidViewModel.

We can now observe our location updates @ any activity/fragment using LiveData, and assign our LifecycleObserver like below:

class MyActivity : AppCompatActivity() {  private val viewModel: MyViewModel by lazy {     return@lazy ViewModelProviders.of(this@MyActivity).get(MyViewModel::class.java) }  override fun onCreate(savedInstanceState: Bundle?) {     super.onCreate(savedInstanceState)     viewModel.addLocationUpdates(lifecycle) } } 

Please note: there's still lot to cover but making this answer as short as possible. So, if you're still confused about something related then please feel free to ask me in comment. I will edit my answer.

like image 22
Jeel Vankhede Avatar answered Nov 02 '22 04:11

Jeel Vankhede