Getting Started
about MVP
The MVP's starting point is separation of concerns, decoupling the view from the business logic. Model-view-presenter three sections can be simply understood as: model is the data that will be displayed in the view. The view is the interface that displays the data (model), and the user instruction (event) is sent to presenter for processing. View usually contains a reference to presenter. Both Activity,fragment and ViewGroup play the role of the view in Android. Presenter is a middleman, and there is a reference to both. Please note that the word model is very misleading. It should be the business logic that gets or processes the model. For example, if your database table is stored with user, and your view wants to display a list of users, then presenter will have a reference to the database business logic (such as DAO) class, presenter it to query the list of users.
Thinking: What is the difference and connection between MVC,MVP and MVVM.
Negative view: In MVP, view is a negative view (Passive views), which means that it tries not to take the initiative, but instead lets presenter control the view in an abstract way, such as presenter Call View.showloading () method to display the load effect, but presenter should not control the specific implementation of the view, such as animations, so presenter should not call View.startanimation ().
Mosby Introduction
Design goal: Allows you to build Android apps with a clear model-view-presenter architecture.
Note: Mosby is a library, not a framework (framework).
Think: what is a library. What is the framework. What is the difference between them.
The Mosby kernel is a very compact library based on the delegate mode (delegation). You can use delegates (delegation) and combinations (composition) to integrate Mosby into your development technology stack. This way you can avoid the constraints and constraints imposed by the framework.
Think: What is the delegate mode. What is the difference between a delegate and an inheritance? What are the benefits of using a delegate.
Depend on:
Mosby is divided into modules, you can choose the functions you need:
dependencies {
compile ' com.hannesdorfmann.mosby:mvp:2.0.1 '
compile ' com.hannesdorfmann.mosby:viewstate : 2.0.1 '
}
Hello MVP World
First to use the Mosby MVP Library to achieve a simple function, the page has two buttons and a textview, the requirements are as follows: Click the Hello button to display the red text "Hello" + random number; Click the Goodbye button to display the blue text "Goodbye" + Random number;
Assuming that the generation of random numbers involves complex business logic calculations, it is a time-consuming operation that takes 2s.
The first step is to implement the business logic of this simulation with a asynctask, in a custom asynctask, to define a listener to pass the results of the business logic execution:
public class Greetinggeneratortask extends Asynctask<void, Void, integer>{
//Callback-listener
Public Interface greetingtasklistener{
void ongreetinggenerated (String greetingtext);
......
Simulates the calculation process and returns a random value.
@Override
protected Integer doinbackground (Void ... params) {
try {
thread.sleep ()
} catch (Interruptedexception e) {
e.printstacktrace ();
}
return (int) (Math.random () *);
}
@Override
protected void OnPostExecute (Integer randomint) {
listener.ongreetinggenerated (Basetext + "" + randomint);
}
}
The second step defines the view interface, and the view interface needs to inherit Mvpview:
Public interface Helloworldview extends mvpview{
void Showhello (String greetingtext);
void Showgoodbye (String greetingtext);
}
Note that the Mvpview here is the top-level interface for all views, it is an empty interface, and no method is defined.
The third step of implementing Presenter,presenter requires executing the business logic and invoking the corresponding method of the view for different execution results.
The top-level interface of the presenter is Mvppresenter, which has two methods:
Public interface Mvppresenter<v extends mvpview> {
/**
* Attaches view to Presenter */
public
Void Attachview (V view);
/**
* Called when the view is destroyed. Typical scenarios are the Activity.ondestroy () and Fragment.ondestroyview () methods */public
void Detachview (Boolean retaininstance);
Mosby provides the base class implementation of the Mvppresenter interface, where we inherit Mvpbasepresenter:
public class Helloworldpresenter extends mvpbasepresenter
Note the processing of background tasks is canceled in the Detachview method.
The fourth step is to implement activity, let our activity inherit mvpactivity, and implement Helloworldview interface.
Mvpactivity has two generics, each of which is the specific type of presenter and view:
public class Helloworldactivity extends Mvpactivity
After inheriting mvpactivity, only one abstract method Createpresenter () needs to be implemented:
Public Helloworldpresenter Createpresenter () {
return new Helloworldpresenter ();
}
Helloworldview There are two other ways to implement:
@Override public
void Showhello (String greetingtext) {
greetingtextview.settextcolor (color.red);
Greetingtextview.settext (Greetingtext);
}
@Override public
void Showgoodbye (String greetingtext) {
greetingtextview.settextcolor (color.blue);
Greetingtextview.settext (Greetingtext);
}
After clicking the button, use presenter to complete the operation:
@OnClick (R.id.hellobutton) public
void onhellobuttonclicked () {
Presenter.greethello ();
}
@OnClick (R.id.goodbyebutton) public
void ongoodbyebuttonclicked () {
presenter.greetgoodbye ();
}
base class for Mvppresenter
Presenter the default implementation of one: Save the view reference with a weak reference, and you must determine isviewattached () before calling GetView ().
public class Mvpbasepresenter<v extends mvpview> implements mvppresenter<v> {
private weakreference <V> Viewref;
@Override public void Attachview (V view) {
viewref = new weakreference<v> (view);
}
@Nullable public V GetView () {
return viewref = = null? Null:viewRef.get ();
}
public Boolean isviewattached () {
return viewref! = null && viewref.get ()! = null;
}
@Override public void Detachview (Boolean retaininstance) {
if (viewref! = null) {
viewref.clear ();
Viewref = null;}}
}
Presenter default implementation two: Use null Object Pattern, no need to judge when calling GetView ().
public class Mvpnullobjectbasepresenter<v extends mvpview> implements mvppresenter<v> {
private V view;
@Override public void Attachview (V view) {
This.view = view;
}
@NonNull public V GetView () {
if (view = = null) {
throw new NullPointerException ("Mvpview reference is null. Have you called Attachview ()? ");
return view;
}
@Override public void Detachview (Boolean retaininstance) {
if (view! = null) {
type[] types =
((parameteri Zedtype) GetClass (). Getgenericsuperclass ()). Getactualtypearguments ();
Class<v> Viewclass = (class<v>) types[0];
View = Noop.of (Viewclass);}}}
Think: What is the empty object pattern (null, the pattern). Basic LCE View
In developing Android apps, we find that many pages have similar structure and UI logic, so we often write duplicate code. If you can abstract a similar page of the View interface, and then encapsulate the base class of the page, you can make development a lot easier. Mosby provides us with a view template called Lce view.
LCE represents loading-content-error (Load-Content-error), which has three states: Display loading, display data content, or display an incorrect view. For example, in the following scenario:
Suppose we want to display a list of countries in the ListView, the data from the country list is taken from the network and is a time-consuming operation. During the loading process, we want to display a ProgressBar, and if the load is wrong, we will display an error message. Also, use Swiperefreshlayout to allow the user to drop the refresh.
The LCE view interface is defined as follows:
Public interface Mvplceview<m> extends Mvpview {
/**
* Display load view, the ID of the load view must be r.id.loadingview
*
/ public void Showloading (Boolean pulltorefresh);
/**
* Display the content view, the content view must have an ID of r.id.contentview
* * <b>the content view must has the
id = R.id.contentview </b>
*
/public void showcontent ();
/**
* Display error view, error view must be textview,id must be r.id.errorview
*
/public void ShowError (Throwable e, Boolean Pulltorefresh);
/**
* Sets the data to be displayed in Showcontent () */public
void SetData (M data);
/**
* Loading data, this method often needs to call the corresponding method of presenter. Therefore, this method cannot be
used in presenter * to avoid cyclic invocation.
* Parameter Pulltorefresh Indicates whether this load is triggered by a drop-down refresh.
*
/public void LoadData (Boolean pulltorefresh);
}
Thinking: The LCE view considers the pull-down refresh, but does not consider the pull-up load, if the server is a paging interface, need to add pull-up loading, how should define the View interface. mvplceactivity and Mvplcefragment
Mosby encapsulates the base class of the LCE view, and now we use mvplceactivity or mvplcefragment to implement the scenario described above for loading the list of countries.
The first step is to finish the interface layout, note that the ID must use the name specified above, the error view can only be a textview:
<framelayout xmlns:android= "http://schemas.android.com/apk/res/android"
......>
<include layout = "@layout/loading_view"/>
<include layout= "@layout/error_view"/>
< Android.support.v4.widget.SwipeRefreshLayout
android:id= "@+id/contentview"
......>
<listview ....../>
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>
The second step is to inherit mvplceview to implement your own view interface, where you need to specify generics as the data type:
Public interface Countriesview extends mvplceview<list<country>>{
}
The third part implements presenter, where we do an interface and an implementation:
Interface Definition:
Public interface Countriespresenter extends mvppresenter<countriesview>{
void Loadcountries (Final Boolean Pulltorefresh);
}
Specific implementation:
public class Simplecountriespresenter extends mvpnullobjectbasepresenter<countriesview> implements Countrie spresenter{. @Override public void Loadcountries (final Boolean Pulltorefresh) {GetView (). Show
Loading (Pulltorefresh); ... countriesloader = new Countriesasyncloader (++failingcounter% 2! = 0, New Countriesasyncloader.countrieslo
Aderlistener () {@Override public void onsuccess (list<country> countries) {
GetView (). SetData (countries);
GetView (). Showcontent (); } @Override public void OnError (Exception e) {GetView (). ShowError (E, Pulltorefre
SH);
}
});
Countriesloader.execute ();
}
......
}
All four methods except LoadData () in Mvplceview are used in the code above.
The fourth step is to implement activity or fragment, take activity as an example, need to inherit mvplceactivity: