Ad

Questions About The Responsbilities Of Each Component In Android Architecture Components

I've been using MVP for a long time now and I'm starting to transfer to a hybrid state between MVP and MVVM

In detail my apps will go like this:

  • Each Activity has a 0 to x Fragments that represent its views
  • Each Fragment will request the Activity's ViewModel so that they can retrieve data using LiveData
  • The Activity will have a seperate ViewModel which will act as the presenter. On creation that ViewModel will be injected with the Activity's ViewModel with the LiveData so that it can update the UI as needed
  • The presenter will get the messages sent to the data ViewModel and send the results back to it

My questions:

  1. Could holding a reference to the data ViewModel in the presenter ViewModel cause a memory leak or adverse effects such as memory leaks?
  2. Where should business logic be? in the presenter or in the model part?

For example, let's say I have a list of items and the user long presses one to edit them, what part of this architecture should be responsible for checking if the user has permission to do this and either let them edit the item or show an error message?

  1. Is there a way for the Fragments to only get part of the Activity's ViewModel?

For example , assuming the activity has 3 Fragments under it, and one ViewModel to cater to them

Can I use something like:

class MainViewModel : ViewModel() , IFragmentA, IFragmentB, IFragmentC

and then when I try to get the ViewModel in the fragments I can write something like:

lateinit var viewModel: IFragmentA

override fun onAttach(context: Context?) {
    super.onAttach(context)
    vm = ViewModelProviders.of(context as AppCompatActivity).get(IFragmentA::class.java)
}

note:I know the above code does not work , what I am asking is if there is a way for something similar to this could work

  1. Is the correct way to send back messages to the activity SingleEvents?

For example, if the user tries to delete an entry , and I wish for them to enter a password, would the flow be:

  • The Fragment sends the message to delete to its ViewModel
  • The ViewModel passes it on to the Presenter
  • The Presenter decides that it needs password verification before moving on
  • The presenter sets the value of a SingleEvent in ViewModel
  • The ViewModel notifies the event's subscribers (in this case the MainActivity) that they should show a dialog asking for a password

Thank you for any help you can provide

Ad

Answer

I have recently ported one of my app from MVP to MVVM architecture. it doesn't matter whether you do it partially or completely, you are moving towards something great and clean and you are going to like it.

Before checking the answer please have a look at this MVVM architecture diagram and some of it's dos and don'ts

MVVM Architecture

Let's look at the roles of each classes here.

Activity/Fragment:

-Listen to MutableLiveData Obeservers and set Data to the views, no other logics here.

ViewModel

  • user input Validations (username, password empty or null checks)
  • set your mutableLive
  • ask repository to start a task network or localdatastorage(sqlite), with callbacks.

Repository

  • cache required data.
  • should not hold any reference to ViewModel this will create a circular dependency.
  • Decides what to do - whether to make network call or load data from local storage. manipulation of the data received goes here(business logic).
  • use the callback received from ViewModel to update data to viewModel, strictly no direct communication.

RemoteDataSource

  • makes a network call and gives the data received back to the repository.

LocalDataSource

  • handles all SQLite related stuff and gives the requested data through callbacks.

there is a todo app sample project from google which uses MVVM. please refer it, it will be very helpful.

  1. No presenter - check user inputs on viewmodel and communicate forth using repository and back using MutableLiveData.
  2. Do your business logic in Repository, consider it more like a model in mvp pattern.
  3. You can have single viewModel for your activity and its fragments. All your fragments communicate through one viewModel. So Each Fragment will only react to the LiveDataObserver it listens to.

There is actually an example of this use case in the Google sample project for MVVM.

AddEditTaskActivity.java

public static AddEditTaskViewModel obtainViewModel(FragmentActivity activity) {
       // Use a Factory to inject dependencies into the ViewModel        
 ViewModelFactoryfactory= ViewModelFactory.getInstance(activity.getApplication());
 return ViewModelProviders.of(activity, factory).get(AddEditTaskViewModel.class);
   }

AddEditTaskFragment.java

 @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final View root = inflater.inflate(R.layout.addtask_frag, container, false);
        if (mViewDataBinding == null) {
            mViewDataBinding = AddtaskFragBinding.bind(root);
        }

        mViewModel = AddEditTaskActivity.obtainViewModel(getActivity());

        mViewDataBinding.setViewmodel(mViewModel);
        mViewDataBinding.setLifecycleOwner(getActivity());

        setHasOptionsMenu(true);
        setRetainInstance(false);

        return mViewDataBinding.getRoot();
    }

  1. Password Verification Flow:
    • fragment ask the ViewModel to deleteEntry.
    • Ask repository to decide whether verification is necessary, with the data which we already have or communicating with the local data source.
    • ViewModel receives a callback from Repository saying verification needed, ViewModel updates the respective MutableLiveData showVerification.postValue(true);
    • As the activity is listening to the showVerificationObserver, it shows the verification UI.

Hope it helps.

Ad
source: stackoverflow.com
Ad