Reacting to activity lifecycle in ViewModel

白昼怎懂夜的黑 提交于 2021-02-18 04:38:08

问题


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?


回答1:


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);
  }
}



回答2:


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.



来源:https://stackoverflow.com/questions/52566018/reacting-to-activity-lifecycle-in-viewmodel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!