Introducing MVVM (Model-View-ViewModel) Architecture in Phimpme Android App
Phimpme Android App an image editor app that aims to replace proprietary photographing and image apps on smartphones. It offers features such as taking photos, adding filters, editing images and uploading them to social networks. The app was using MVP(Model-View-Presenter) architecture and is now being ported to MVVM(Model-View-ViewModel) architecture.
Advantages of MVVM over MVP?
- The view model is lifecycle aware and only updates the UI based on the lifecycle of the activity/fragment.
- Separation of concerns – Not all the code under one single activity
- Loose coupling – Activity depends on ViewModel and ViewModel depends on the Repository and not the other way around.
MVVM?
- Model – Model represents the data and business logic of the app. The repository can be seen as a model in an MVVM architecture which contains login to fetch the data from an API or a remote API
- ViewModel – The view model creates a reference with Model/Repository and gets the data for the UI. It delivers the data to UI via observers of LiveData and also the ViewModel is lifecycle aware and respects the lifecycle of the activity such as screen rotations that don’t cause the ViewModel to be created again.
- View – The Activity/Fragment is the view where the data is shown to the user, the View creates a reference to the ViewModel via ViewModel provider class. Hence it listens to the ViewModel callbacks via LiveData.
Process for inclusion
- Add ViewModel and LiveData
implementation "androidx.lifecycle:lifecycle-extensions:$rootProject.lifecycleVersion"
- Now create a class AccountViewModel – it will perform all the functioning that will drive the UI of the Account Activity. We will use LiveData for observing the data in the activity
public class AccountViewModel extends ViewModel {
private AccountRepository accountRepository= new AccountRepository();
MutableLiveData<RealmQuery<AccountDatabase>>accountDetails = new MutableLiveData<>();//live data}
- Create a class AccountRepository – Used to perform the DB related operations and the ViewModel will hold the instance of this repository.
class AccountRepository {
private Realm realm = Realm.getDefaultInstance();
private DatabaseHelper databaseHelper = new DatabaseHelper(realm);// Fetches the details of all accounts present in database
RealmQuery<AccountDatabase> fetchAllAccounts() {
return databaseHelper.fetchAccountDetails();
}
} - Now we will add the functionality in AccountViewModel to fetch accounts for the UI
public class AccountViewModel extends ViewModel {
final int RESULT_OK = 1;
private AccountRepository accountRepository = new AccountRepository();
MutableLiveData<Boolean> error = new MutableLiveData<>();
MutableLiveData<RealmQuery<AccountDatabase>> accountDetails = new MutableLiveData<>();
public AccountViewModel() {}
// Used to fetch all the current logged in accounts
void fetchAccountDetails() {
RealmQuery<AccountDatabase> accountDetails = accountRepository.fetchAllAccounts();
if (accountDetails.findAll().size() > 0) {
this.accountDetails.postValue(accountDetails);
} else {
error.postValue(true);
}
} - Now in the AccountActivity, we will have the reference of ViewModel and then observe the liveData error and accountDetails
public class AccountActivity extends ThemedActivityimplements RecyclerItemClickListner.OnItemClickListener {
private AccountViewModel accountViewModel;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ButterKnife.bind(this);
ActivitySwitchHelper.setContext(this);
setSupportActionBar(toolbar);
//fetching the viewmodel from ViewModelProviders
accountViewModel = ViewModelProviders.of(this).get(AccountViewModel.class);
initObserver();
}
private void initObserver() {
accountViewModel.error.observe(this, value -> {
if (value) {
SnackBarHandler.create(coordinatorLayout, getString(no_account_signed_in)).show();
showComplete();
}
});
accountViewModel.accountDetails.observe(this, this::setUpAdapter);
}
Hence, this completes the implementation of MVVM Architecture in the Phimpme app.
Resources
- Guide to App Architecture – Android Developers Blog
- ViewModel Overview – Android Developers Blog
- LiveData Overview – Android Developers Blog
Link to the Issue: https://github.com/fossasia/phimpme-android/issues/2889
Link to the PR: https://github.com/fossasia/phimpme-android/pull/2890