♻️Helper classes to build Android Apps through MVP pattern in a faster way
This library exposes a minimal API, that should help you to build well architected Android Apps. ¡Check the following steps to get up and running!
Actually I don't have this library in JCenter/Maven Central, so if you want to use, follow the instructions. The library is distributed for Java and Kotlin. Looking for Kotlin variant? Go here
Gradle
allprojects {
repositories {
...
maven {
url "https://jitpack.io"
}
}
}
dependencies {
compile 'com.github.BlackBoxVision:mvp-helpers:v0.2.0'
}
Maven
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>com.github.BlackBoxVision</groupId>
<artifactId>mvp-helpers</artifactId>
<version>v0.2.0</version>
</dependency>
SBT
resolvers += "jitpack" at "https://jitpack.io"
libraryDependencies += "com.github.BlackBoxVision" % "mvp-helpers" % "v0.2.0"
The concepts behind this library are the following ones:
View → The View is an interface that contains methods related to UI interaction. Those methods should be implemented in your Activity, Fragment or View.
Interactor → The Interactor is the class that do the hard work, all the blocking operations like I/O, Networking, Database Intectations should be done here.
Presenter → The presenter acts as a middle man between the Interactor and the View.
The usage is really simple:
1 - Create your View interface by extending the BaseView. BaseView is an empty interface that acts as water mark for the Presenter.
public interface DetailsView extends BaseView {
void onInfoReceived(@NonNull Bundle information);
void onInfoError(@NonNull String errorMessage);
}
2 - Create an Interactor class by extending the BaseInteractor class. The BaseInteractor provides you a set of helper methods to deal with background execution and UIThread interaction. The methods are the following ones:
//This example uses Java 8 features, I assume the usage of retrolambda
public final class DetailsInteractor extends BaseInteractor {
public void retrieveDetailsFromService(@NonNull final String id, @NonNull final OnSuccessListener<Bundle> successListener, @NonNull final OnErrorListener<String> errorListener) {
runOnBackground(() -> {
//Getting data from somewhere
final Bundle data = MockUtils.getMockedData(id);
runOnUiThread(() -> {
if (data != null) {
successListener.onSuccess(data);
} else {
errorListener.onError("Ups, something went wrong");
}
});
});
}
}
3 - Create a Presenter class by extending the BasePresenter class. The BasePresenter provides you with a set of helper methods to deal with View management. The methods are the following ones:
//I use method references from Java 8 to point the callbacks to interactor, I assume a working project with Retrolambda
public final class DetailsPresenter extends BasePresenter<DetailsView> {
private DetailsInteractor interactor;
@Override
protected void onViewAttached(@NonNull DetailsView view) {
interactor = new DetailsInteractor();
}
@Override
protected void onViewDetached() {
interactor = null;
}
public void findRequiredInformation(@NonNull String id) {
if (isViewAttached()) {
interactor.retrieveDetailsFromService(id, this::onSuccess, this::onError);
}
}
private void onSuccess(@NonNull Bundle information) {
if (isViewAttached()) {
getView().onInfoReceived(information);
}
}
private void onError(@NonNull String errorMessage) {
if (isViewAttached()) {
getView().onInfoError(errorMessage);
}
}
}
4 - Create a custom PresenterFactory class to provide the presenter instance. You should implement the PresenterFactory interface.
Now we have to create a Factory, because I have recently implemented a way to not loose presenter when configuration changes. The BaseActivity/BaseFragment use a Loader to provide the Presenter instance, Android Loaders can survive configuration changes, that's why I select them.
class DetailsPresenterFactory implements PresenterFactory<DetailsPresenter> {
@Override
public DetailsPresenter create() {
return new DetailsPresenter();
}
}
5 - Attach this cycle with Android specific classes. You can choice an Activity/Fragment or also a custom view. In this case I will show you an example with Fragment that inherits from BaseFragment
The BaseFragment comes with a resumed lifecycle, and a set of methods to implement. The methods are the following ones:
public final class DetailsFragment extends BaseFragment<DetailsPresenter, DetailsView> implements DetailsView {
@Override
protected DetailsPresenterFactory createPresenterFactory() {
return new DetailsPresenterFactory();
}
@LayoutRes
@Override
protected int getLayout() {
return R.layout.fragment_details;
}
@Override
protected void onPresenterCreated(@NonNull DetailsPresenter presenter) {
//Do something when presenter it's created
getPresenter().getInformationFromId("ssdWRGD132");
}
@Override
protected void onPresenterDestroyed() {
//Do something when presenter is removed, this method is called in onDestroy
}
@Override
void onInfoReceived(@NonNull Bundle information) {
Toast.makeText(getContext(), information.toString(), Toast.LENGTH_SHORT).show();
}
@Override
void onInfoError(@NonNull String errorMessage) {
Toast.makeText(getContext(), errorMessage, Toast.LENGTH_SHORT).show();
}
}
From version 0.2.0 of this library, I have decided to remove butterKnife, in order to not force any dev to use butterKnife.
If you found a bug, or you have an answer, or whatever. Please, open an issue. I will do the best to fix it, or help you.
Of course, if you see something that you want to upgrade from this library, or a bug that needs to be solved, PRs are welcome!
0.2.0
0.1.0
0.0.3
0.0.2
0.0.1
Distributed under the MIT license. See LICENSE for more information.