8

I am following MMVM architecture in app, Everything was working fine untill I got a crash using following code to start an activity from ViewModel. Method is called from XML using databindings and passing view as parameter and getApplication() is the method from AndroidViewModel class.

getApplication().startActivity(new Intent(view.getContext(), MyActivity.class));

I believe it was because I am not using NEW_TASK flag since I am starting activity outside an Activity class.

Now there are following solutions I could think of but not sure which one is best based on architectural point of view.

1. ViewModel with a method which takes Activity as parameter and call that method from a fragment

public startMyActivity(Activity activity){
   activity.startActivity(new Intent(activity, MyActivity.class));
}

Now add a listner something like this in fragment

mBinding.myButton.setOnClickListener(){
    viewModel.startMyActivity(getActivity());  
}

2. Adding a New Task flag to intent and keep it in ViewModel itself

Intent myIntent = new Intent(view.getContext(), MyActivity.class);
myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
getApplication().startActivity(myIntent);

3. Start the Activity from fragment itself

mBinding.myButton.setOnClickListener(){
   activity.startActivity(new Intent(activity, MyActivity.class));
}

I believe all these approaches works fine but a question in mind

Is it ok to have listeners seprately in Fragment insted of using binded ViewModels to call method from view xml ?

I am not sure about the second approach if that will still crash the app in some OS.

Which one is the best approach from architecture point of view and unit test prespective ?

Piyush Agarwal
  • 25,608
  • 8
  • 98
  • 111
  • One must avoid using any android views in ViewModel or AndroidViewModel. – Chintan Soni Mar 15 '18 at 05:38
  • @ChintanSoni I agree, It is not a reference it passes from databinding on click listeners method, I belive this should be fine. – Piyush Agarwal Mar 15 '18 at 05:41
  • @MuhammadBabar who should start the activity then and how because ideally all view interactions should be handled in view models. – Piyush Agarwal Mar 15 '18 at 05:45
  • Yes you are right, Well it depends, if you have activity context available then it's best to use, `NEW_TASK` is commonly used the activity context is not available for example in a broadcast receiver or a service etc. – Muhammad Babar Mar 15 '18 at 05:49

1 Answers1

8

I would go for navigation inside activities/fragments but of course most case you wanna trigger your navigation from view model. So you need to use a command from you view model to notify your view (activity/fragment) to navigate elsewhere. You can do this kind of "command" using LiveData and more specificly SingleLiveEvent.

SingleLiveEvent is like any LiveData but trigger an event only when you explicity set a value to it, for example you won't receive its value when starting observing it from your view (activity/fragment)

Samuel Eminet
  • 4,647
  • 2
  • 18
  • 32