In this article, I’m going to explain the implementation of MVP architecture using Dagger 2, ButterKnife, Room Persistence, Rxjava 2, RxAndroid, Retrofit, logging and debugging. In this Android tutorial, we will build project that contains Architect Android Apps with MVP, Dagger, Retrofit & Rxjava.
I will share repository that contains all above library implementation following best practices. We create superior design in such way that it could be inherited and maximize the code reuse.
To order to build a clean code in the MVP architecture, some tool and frameworks are needed. These are Dagger2, Retrofit, RxJava, RoomPersisstense It will be good to understand how each of these libraries plays a specific part in the role to build better code. There almost industries standard of build a modern application for Android.
Prerequisite
As this article we are using many libraries, So you need to have knowledge of each one library. because in this sample app all library integrated with depends on one another. I recommend you got through MVP Architect Sample Application Tutorials Series.
MVP Architect Sample Application Tutorials Series
- MVP :- https://androidwave.com/android-mvp-architecture-for-beginners-demo-app/
- Dagger2 :- https://androidwave.com/dagger2-android-example/
- RxJava2:- https://androidwave.com/rxjava-rxandroid-tutorials/
- Retrofit:- https://square.github.io/retrofit/
- Room Persistence:- https://androidwave.com/working-with-room-persistence-library/
- Debugging and Logging:- https://androidwave.com/useful-tools-for-logging-debugging-in-android/
- Downloadable Font:- https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
- Globally Error Handling – https://androidwave.com/retrofit-globally-error-handling/
The app has following packages:
- data: It contains all the data accessing and manipulating components.
- Room Persistence (Local Database )
- Networking stuff (REST APIs call)
- Shared Preferences.
- : Dependency providing classes using Dagger 2.
- Components
- Module
- ui: View classes along with their corresponding Presenters.
- Views
- Custom Components
- Activity, fragment
- : Services for the application.
- All service and Job IntentService should be placed here.
- utils: Utility classes.
- All utility class write in this package

How to use this repo
Project Setup
Go to the root directory of
$ git clone https://github.com/droidwave/MVP-Architect-Android-Apps.git
After taking successful clone you have to do following changes
- Rename package name – Follow this article for
rename package name - Replace values in build
.gradle such as BASE_URL and API_KEY with your server configuration
Brief Intro of Repo
In this repo, we have created a separate package for each module or functionality. For all user interface part is placed in

Follow below step for create a new activity
- Just create a new package name like profile. Now go to
file menu and create a new activity named is ProfileActivity. - Now extends the BaseActivity instance of AppCompatActivity and override setUp() methods.
package com.androidwave.cleancode.ui.profile; import android.os.Bundle; import com.androidwave.cleancode.R; import com.androidwave.cleancode.ui.base.BaseActivity; public class ProfileActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_profile); } @Override protected void setUp() { } }
- Create a new interface name is ProfileMvpView which extends MvpView and declare all UI operation methods here such as updateProfile(UserProfile profile) for as per need
package com.androidwave.cleancode.ui.profile; import com.androidwave.cleancode.data.network.pojo.UserProfile; import com.androidwave.cleancode.ui.base.MvpView; /** * Created on : Feb 17, 2019 */ public interface ProfileMvpView extends MvpView { void updateProfile(UserProfile profile); }
- Furthermore, create a new interface with names PofileMvpPresenter<V extends ProfileMvpView> which extends MvpPresenter<V>. The view is here type of View. Here you declare all data related methods. For example network operation, fetching data from local DB etc.
package com.androidwave.cleancode.ui.profile; import com.androidwave.cleancode.ui.base.MvpPresenter; /** * Created on : Feb 17, 2019 */ public interface ProfileMvpPresenter<V extends ProfileMvpView> extends MvpPresenter<V> { void onViewPrepared(); }
- Create a new presenter with name ProfilePresenter which extends BasePresenter and implementing PofileMvpPresenter. After that override super constructor and annotated with @Inject annotations like below
- Now open ProfileActivity and implement ProfileMvpView.
package com.androidwave.cleancode.ui.profile; import com.androidwave.cleancode.data.DataManager; import com.androidwave.cleancode.ui.base.BasePresenter; import com.androidwave.cleancode.utils.rx.SchedulerProvider; import io.reactivex.disposables.CompositeDisposable; /** * Created on : Feb 17, 2019 * Author : AndroidWave */ public class ProfilePresenter<V extends ProfileMvpView> extends BasePresenter<V> implements ProfileMvpPresenter<V> { public ProfilePresenter(DataManager manager, SchedulerProvider schedulerProvider, CompositeDisposable compositeDisposable) { super(manager, schedulerProvider, compositeDisposable); } @Override public void onViewPrepared() { getMvpView().showLoading(); getCompositeDisposable().add(getDataManager() .getUserProfile(String.valueOf(getDataManager().getUserId())) .subscribeOn(getSchedulerProvider().io()) .observeOn(getSchedulerProvider().ui()) .subscribe(response -> { if (!isViewAttached()) { return; } getMvpView().hideLoading(); /** * Update view here */ getMvpView().updateProfile(response.getData()); }, error -> { if (!isViewAttached()) { return; } getMvpView().hideLoading(); /** * manage all kind of error in single place */ handleApiError(error); })); } }
- After that, you have to write a DI code for providing presenter here > base package => di =>module => ActivityModule
@Provides @PerActivity ProfileMvpPresenter<ProfileMvpView> provideProfilePresenter(ProfilePresenter<ProfileMvpView> presenter) { return presenter; }
- Finally, Open ProfileActivity and attached presenter with view
package com.androidwave.cleancode.ui.profile; import android.os.Bundle; import com.androidwave.cleancode.R; import com.androidwave.cleancode.data.network.pojo.UserProfile; import com.androidwave.cleancode.ui.base.BaseActivity; import javax.inject.Inject; public class ProfileActivity extends BaseActivity implements ProfileMvpView { @Inject ProfileMvpPresenter<ProfileMvpView> mPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_profile); getActivityComponent().inject(this); mPresenter.onAttach(ProfileActivity.this); setUp(); } @Override protected void setUp() { } @Override public void updateProfile(UserProfile profile) { } }
- Open ActivityComponent from di =>components => ActivityComponent and add bellow code
void inject(ProfileActivity profileActivity);
Finally, Your activity is ready to run, Almost same step you have to follow for fragment.
How to add RestApi
We have to follow some basic steps to add RestAPIs in this repos, as you seeing BaseDataManager class is responsible for handle all type data such as Rest APIs, PreferencesManager and local DB also.
- Just navigate to base package=> data => network => NetworkService and add retrofit calling methods
package com.androidwave.cleancode.data.network; import com.androidwave.cleancode.data.network.pojo.FeedItem; import com.androidwave.cleancode.data.network.pojo.LoginRequest; import com.androidwave.cleancode.data.network.pojo.UserProfile; import com.androidwave.cleancode.data.network.pojo.WrapperResponse; import java.util.List; import io.reactivex.Single; import retrofit2.http.Body; import retrofit2.http.GET; import retrofit2.http.POST; import retrofit2.http.Path; /** * Created on : Jan 19, 2019 * Author : AndroidWave */ public interface NetworkService { /** * @return Observable feed response */ @GET("feed.json") Single<WrapperResponse<List<FeedItem>>> getFeedList(); @POST("login") Single<WrapperResponse<UserProfile>> doLoginApiCall(@Body LoginRequest mRequest); // here is api that fetching user details @GET("user/profile/{user_id}") Single<WrapperResponse<UserProfile>> getUserProfile(@Path("user_id") String userId); }
- Now open RestAPI manager and one methods for dealing getProfile API
package com.androidwave.cleancode.data.network; import com.androidwave.cleancode.data.network.pojo.FeedItem; import com.androidwave.cleancode.data.network.pojo.LoginRequest; import com.androidwave.cleancode.data.network.pojo.UserProfile; import com.androidwave.cleancode.data.network.pojo.WrapperResponse; import java.util.List; import io.reactivex.Single; public interface RestApiHelper { Single<WrapperResponse<UserProfile>> doLoginApiCall(LoginRequest request); Single<WrapperResponse<List<FeedItem>>> getFeedList(); // add this line of code Single<WrapperResponse<UserProfile>> getUserProfile(String userId); }
- Now override this method in all subclass. Open RestApiManager and add below line
@Override public Single<WrapperResponse<UserProfile>> getUserProfile(String userId) { return mService.getUserProfile(userId); }
- Finally, Open base BaseDataManager and add an unimplemented method like below
@Override public Single<WrapperResponse<UserProfile>> getUserProfile(String userId) { return mApiHelper.getUserProfile(userId); }
4 Comments
em getting error on gradle build
can you share error
Can the tutorial go through all files please
You can download full source code from the above link. All file display is not possible