How it works - mandriana/android-mvp-core GitHub Wiki
This section goal is to present the library architecture behind the fact that it is MVP.
The core library contains minimal requirements to use the MVP architecture.
The implementation relies on retaining the presenters in a PresenterCache
to keep them alive across orientation change. Presenters can be manipulated using the PresenterController
class. This controller can be used to attach / detach the view to the presenter, retrieve a presenter from the cache (see PresenterController)
A presenter should extends the abstract class Presenter
. A presenter has a lifecycle and can be notified of the times the view is attached to the presenter or detached. Available methods for override are :
-
onCreate
: called when the presenter is created (instantiated) -
onCreateThenAttached
: called the first time the view is attached to the presenter -
onViewAttached
: called when the view is attached -
onViewDetached
: called when the view is detached -
onDestroy
: called when the presenter is destroyed
A presenter can access the view through the method getView()
which is annotated @Nullable
. This method does need to be checked against null
to access view members or properties.
The RxPresenter is a base presenter which provides features to perform task using RxJava with many benefits :
- no need to use the
getView()
to dispatch results to the view, meaning no null check - ability to start observables and cancel them
- ability to retrieve observables result even after an orientation change or a pause and resume
The full method to start observables is :
public <Result> void start(@NonNull final String tag,
@NonNull Observable<Result> observable,
boolean withDefaultSchedulers,
@Nullable final OnNext<V, Result> onNext,
@Nullable final OnError<V> onError,
@Nullable final OnCompleted<V> onCompleted)
The parameters of this methods are :
- tag : a tag to identify a task which will be used in case of cancellation
- observable : the observable to execute
- withDefaultSchedulers : a boolean to set to use default schedulers which are
observable.observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io())
- onNext : on next action with two parameters which are typed on the view type V and result type Result
- onError : on error callback with two parameters which are the view and the throwable
- onCompleted : on completed callback with the view as parameter
Shortcuts of this method are also available (RxPresenter)) if you only need the OnNext and OnError callbacks ...
public class MainPresenter extends RxPresenter<MainView> {
private static final String TASK_DO_STUFF = "doStuff";
public void doStuff() {
start(TASK_DO_STUFF, Observable.just(1,2,3,4),
new OnNext<MainView, Integer>() {
@Override
public void call(@NonNull MainView mainView, @NonNull Integer i) {
mainView.onNextItem(i);
}
},
new OnError<MainView>() {
@Override
public void call(@NonNull MainView mainView, @NonNull Throwable throwable) {
mainView.onTaskFailed();
}
},
new OnCompleted<MainView>() {
@Override
public void call(@NonNull MainView mainView) {
mainView.onTaskCompleted();
}
});
}
}
As you can see the view is available inside each callback as a parameter, the getView()
method is not used at all. This ensure onNextItem(i)
, onTaskFailed()
and onTaskCompleted()
are called with a non null view i.e the view is attached.
If you only use the core library, you are responsible for the attach/detach process of your view and presenter.
If you use the mvp-base-view library you can access to a BasePresenterActivity
and a BasePresenterFragment
. These base classes perform all the work for you to tie the view to the presenter.
Constructor injection is now easier with dagger.
There is no need anymore of the functions injectActivity(), injectFragment() and instantiatePresenter() in the BasePresenterActivity
nor BasePresenterFragment
. Instead you can just :
@PresenterClass(MainPresenter.class)
public class MainActivity extends BasePresenterActivity<MainPresenter> implements MainView {
@Override
protected void onCreate(Bundle savedInstanceState) {
MVPApplication.mAppComponent.inject(this);
super.onCreate(savedInstanceState);
...
}
}
This library enhance the core library be providing two ready to use base classes :
BasePresenterActivity
BasePresenterFragment
The abstract methods you must override are :
@NonNull protected abstract P instantiatePresenter();
where you need to instantiate your presenter. Keep in mind that a presenter is instantiated only the first time it is accessed using the getPresenter()
method. If you do not call this method, no instantiation will be performed, avoiding allocating memory for unused presenter.
And :
@NonNull protected abstract PresenterCache getPresenterCache();
where you must return the PresenterCache
instance.
As mentioned previously the view will be attached to the presenter in onResume()
and detached in onPause
. This choice was made to manipulate the view when it is visible to the user. In a next version a configurator will be available to attach view in onStart or onResume and detaching it in the corresponding method.
When a presenter is destroyed using the destroyPresenter()
method, it is removed from the presenter cache.
If you use this class, the presenter will be destroyed automatically when onPause
is called with isFinishing()
returning true or when calling finish()
. You can manually fire a presenter destruction by calling destroyPresenter()
.
With fragments the destruction depends on the call of onPause()
with getActivity().isChangingConfigurations()
returning false. Because fragments lifecycle can be more complex (using view pager for instance), you may have to deal with the presenter destruction yourself when needed using the method destroyPresenter()
.