Open In App

Android MVP Architecture Extension with Interactors and Repositories

Last Updated : 14 Sep, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Nature’s truth is evolution, and new developments are led by natural selection. As a result, there are many diverse species with numerous similarities, and they all adapt best to their environment. The concept that one is superior to the other is only applicable under limited circumstances when one is more suited for survival. When the circumstances change, so does the concept. This is equally true for any software design. In its own right, one answer is superior to the other. As previously stated, several enhancements were discovered in order to better respond to certain conditions. All of these scenarios arose for Android apps with a large codebase and several developers working on the project at the same time.

There were two restrictions found in such conditions:

  • DataManager centralization: In the MVP architecture, the DataManager is meant to outsource all duties to ApiHelper, DbHelper, and PreferenceHelper. It’s an excellent architecture for most use situations since it allows you to intercept Helper calls and do some pre-processing. However, for large projects, this class can grow to be rather huge.
  • DbHelper centralization: The DbHelper was created to get data from the database using the DAO classes. This is also excellent for most projects with fewer DB queries, but it can get extremely huge for large projects.

The problem of centralized DataManager might perhaps be addressed by exposing the Helper instances to the Presenters. This will eliminate the DataManager delegation calls, reducing the codebase to a few functions that need cross Helpers calls or a series of Helper calls. This approach would be a good fit for the existing MVP design. Tapping untapped potential necessitates taking two moves forward once we have arrived at our objective. We now propose some major improvements to the existing MVP design in order to make it appropriate for very big projects with many developers working on it at the same time. Let us begin by identifying the obstacles associated with such initiatives.

Large Project? Don’t worry

Large projects contain numerous features, and in order to manage those features, a modularized codebase is required. Even inside a module, the ideal strategy is to separate the programs such that all of the features are encapsulated, which means that all of the dependencies for that feature may be resolved in its package at most. To allow many developers to collaborate on the same project while avoiding code merges with each pull request, we must provide feature encapsulation.

To learn about Android MVP, just visit here.

DataManager decentralization yields an Interactor structure, whereas DbHelper decentralization yields Repositories.

  1. Interactor: Instead of a singleton DataManager, each Presenter receives its own instance of an Interactor. The interactor has the same duties as the DataManager, but it is solely concerned with the data access and processing calls necessary by the feature it is providing.
  2. The DbHelper is organized into Repositories. For example, all database queries for a User table are performed via a UserRepository rather than the DbHelper. UserRepository, like DbHelper, routes all of its queries through UserDao.

Image #1. The MVP architecture explained.

GeekTip: In contrast to a singleton DbHelper, the Repository is instantiated on demand, and each Interactor receives a new Repository instance.

When compared to the original MVP architectural blueprint we can see that the DataManager and DbHelper have been replaced with Interactors and Repositories, which are available to each Presenter individually.

The MVP architecture has undergone significant changes

gfgMVPInteractor: It is an interface that lists the data access APIs shared by all application components as well as the access methods for the sampleAPIHelper and PreferencesHelper singletons.

Java




public interface gfgMVPInteractor {
    sampleAPIHelper getSampleAPIHelper();
    PreferencesHelper gfgPrefrences();
    void setUserAsLoggedOut();
      // Logging out the user
    void setAccessToken(String accessToken);
      // Setting the user access token
      // Further Code goes here
}


gfgMVPInteractor is implemented by BaseInteractor. This BaseInteractor is extended by all subsequent Interactors. BaseInteractor receives a singleton ApiHelper and a singleton PreferenceHelper. 

Java




public class BaseInteractor implements GFGMVPINTERACTOR {
    private final PreferencesHelper GFGPREFERENCESHELPER;
    private final ApiHelper mApiHelper;
    @Inject
    public BaseInteractor(PreferencesHelper preferencesHelper, ApiHelper SAMPLEAPIHELPER) {
        GFGPREFERENCESHELPER = preferencesHelper;
        mApiHelper = SAMPLEAPIHELPER;
    }
 
    @Override
    public ApiHelper GETSAMPLEAPIHELPER() {
        return mApiHelper;
    }
 
    @Override
    public PreferencesHelper getPreferencesHelper() {
        return GFGPREFERENCESHELPER;
    }
 
    @Override
    public void setAccessToken(String GFGACCESSTOKEN) {
        getPreferencesHelper().setAccessToken(GFGACCESSTOKEN);
        GETSAMPLEAPIHELPER().getApiHeader()
                .getProtectedApiHeader()
                .setAccessToken(GFGACCESSTOKEN);
    }


Component-wise Interactors extend the BaseInteractor and implement an interface that extends the gfgMVPInteractor and includes its own APIs. Example: GfGMvpInteractor is an extension of MvpInteractor that includes doServiceCall, doGoogleLoginApiCall, and doFacebookLoginApiCall. GFGLoginInteractor, like BaseInteractor, extends BaseInteractor and implements GfGLoginMvpInteractor.

Java




public class GFGLOGININTERACTOR extends BaseInteractor
implements LoginMvpInteractor {
    private UserRepository GFGUSERREPOSITORY;
    @Inject
    public GFGLOGININTERACTOR(PreferencesHelper preferencesHelper, ApiHelper SAMPLEAPIHELPER, UserRepository userRepository) {
        super(preferencesHelper, SAMPLEAPIHELPER);
        GFGUSERREPOSITORY = userRepository;
    }
    @Override
    public Observable<LoginResponse> DOSERVICECALL(
            LoginRequest.ServerLoginRequest request) {
        return getApiHelper().DOSERVICECALL(request);
   }


The Presenter is structured similarly to the original MVP architecture, with the exception that the DataManager is replaced with the component’s interactor. GFGLoginMvpPresenter is an example of an interface. In the definition, Interactor has been included beside View.

Example UserRepository

Let’s look at a real-world user repo example to better understand the whole concept:

Java




public class GFGUSERREPOSITORY {
private final GFGDAOSESSION GFGGFGDAOSESSION;
    @Inject
    public GFGUSERREPOSITORY(GFGDAOSESSION GFGDAOSESSION) {
          // A sample GFG DAO session
        GFGGFGDAOSESSION = GFGDAOSESSION;
    }
    public Observable<Long> insertUser(final User user) {
        return Observable.fromCallable(new Callable<Long>() {
            @Override
             // Overriding the method
            public Long call() throws Exception {
                  // Just exceptional Handling
                return GFGGFGDAOSESSION.getUserDao().insert(user);
            }
        });
    }
   // Your other code go here
}


Conclusion

You can see that the login feature components are independent of the rest of the program and have all of their dependencies wrapped. Any developer working on the login function is free to work independently of other developers working on other projects.

These components increase the architecture’s extensibility and flexibility, albeit at the expense of extra labor. I must emphasize that the basic MVP design is suitable for most projects of reasonable complexity, but this expanded version is suitable for very big projects with hundreds of features and several people working on it concurrently. We are really happy to use the original architecture in our app’s codebase.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads