MVP sample implementation effect:

  

Github address: github.com/xurui1995/M…

As always, before we get to the MVP model, let’s talk a little bit more about the MVC model, the weaknesses of MVC. We just figured out why MVP was used.

For MVC diagrams, I found some diagrams on the Internet. As follows:

    

MVC pattern has been widely used in the development of Web or management systems. Our View interacts with people. When people click the mouse or input something, the View will send corresponding instructions to the Controller. After Model is processed, View refreshes.

Disadvantages of the MVC pattern:

1: In Android, if we are going to use the MVC pattern, what does each layer represent?

You might say: View corresponds to The Android layout. XML,Model corresponds to the Android database operations on the network and other operations are placed here, Controller corresponds to the Activity!

You’re right, but don’t you think the correspondence is bad? If layout.xml corresponds to a View, what if we want to dynamically add some View controls or change the background?

Answer: Add code to the Activity. !!!!!!!!! This is one of the drawbacks: The Activity acts as both a View and a Controller, and the View layer represented by layout.xml is too weak to control.

2: Look at the structure diagram of our MVC again. View and Model are interrelated and have coupling relationship, which brings difficulties to test and maintenance. When we want to replace a part in a project, it is too difficult to remove! The methods of this part class are scattered in many places. As for the structure diagram of MVC, I don’t know where I heard the classic saying, write three letters, M, V, C, connect the letters with any line or arrow, and finally the structure diagram of MVC.

Having said MVC, here comes the main character, here’s our MVP structure diagram.

  

The benefit is self-evident: The View and Model can’t communicate.

The View layer is only responsible for the View. The View layer sends events to the Presenter when it manipulates the Model, and the Presenter notifies the View of updates.

More on MVP concepts:

【 例 句 】Android MVP design mode

MVC, MVP, and MVVM diagrams

Next, take a look at how we used the MVP pattern in our project, using Retrofit and RXjava in passing, and I encourage you to understand their usage first.

First look at our requirements: input Github login name, click search button, search and display results (login name, nickname, Followers, following).

Final project structure:

               

The bean class:

public class User { private String login; private String name; private int followers; private int following; public int getFollowers() { return followers; } public void setFollowers(int followers) { this.followers = followers; } public int getFollowing() { return following; } public void setFollowing(int following) { this.following = following; } public String getLogin() { return login; } public void setLogin(String login) { this.login = login; } public String getName() { return name; } public void setName(String name) { this.name = name; }}Copy the code

The RetroFIT class primarily encapsulates network requests that utilize RetroFIT

public interface GithubService {
    @GET("/users/{user}")
    Observable getUser(@Path("user") String username);
}
Copy the code

public class HttpMethods { public static final String BASE_URL = "https://api.github.com"; private static final int DEFAULT_TIMEOUT = 5; private Retrofit retrofit; private GithubService mGithubService; Private HttpMethods() {// Manually create an OkHttpClient and set the timeout OkHttpClient.Builder(); httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS); retrofit = new Retrofit.Builder() .client(httpClientBuilder.build()) .addConverterFactory(GsonConverterFactory.create())  .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .baseUrl(BASE_URL) .build(); mGithubService = retrofit.create(GithubService.class); } private static class SingletonHolder{ private static final HttpMethods INSTANCE = new HttpMethods(); } public static HttpMethods getInstance(){return singletonholder.instance; } public void getUser(Subscriber subscriber ,String loginName){ mGithubService.getUser(loginName) .subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subscriber); }}Copy the code

Thinking about our MVP model, starting with our View layer, we need to list the methods associated with the View (no logic involved).

1. Attempts to display XML

2. The ProgressDialog display

3. The ProgressDialog disappear

4. An error message is displayed

Let’s look at the code:

activity_main.xml




    
    
    Copy the code

Copy the code

BaseView, BasePresentor, BaseModel three interfaces

public interface BaseView {
    void showProgressDialog();
    void hideProgressDialog();
    void showText(User userbean);
    void showErrorMessage(String text);
}
Copy the code

public interface BasePresenter {
    void attachView(T view);
    void detachView();
    void searchUser(String loginName);
}
Copy the code

public interface BaseModel {
    void getUser(Subscriber subscribe,String loginName);
}
Copy the code

The second interface, Interface BasePresenterextends BaseView>, is the key, and the implementation class explains why.

MainActivity implements the BaseView interface as the View layer.

public class MainActivity extends AppCompatActivity implements BaseView { @InjectView(R.id.tv) TextView mTextView; @InjectView(R.id.search_btn) Button mButton; @InjectView(R.id.ed_text) EditText mEditText; private ProgressDialog dialog; private MainPresenter mMainPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.inject(this); initView(); mMainPresenter=new MainPresenter(); mMainPresenter.attachView(this); Private void initView() {dialog=new ProgressDialog(this); dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); Dialog.setmessage (" searching "); } @OnClick(R.id.search_btn) void search(View view){ mMainPresenter.searchUser(mEditText.getText().toString()); } @Override public void showProgressDialog() { dialog.show(); } @Override public void hideProgressDialog() { dialog.dismiss(); } @Override public void showText(User userbean) { String temp=getResources().getString(R.string.user_format); String str=String.format(temp,userbean.getLogin(),userbean.getName(),userbean.getFollowers(),userbean.getFollowing()); mTextView.setText(str); } @Override public void showErrorMessage(String text) { Toast.makeText(this,text,Toast.LENGTH_SHORT).show(); } @Override protected void onDestroy() { super.onDestroy(); if(mMainPresenter! =null) mMainPresenter.detachView(); }}Copy the code

When an event is generated by clicking on a Button, the logic is handed over to MainPresenter (V — > P)

Let’s look at the MainPresenter code and the Model code.

public class MainPresenter implements BasePresenter { private BaseView mMainView; private MainModel mModel; public MainPresenter() { mModel=new MainModel(); } @Override public void attachView(BaseView view) { mMainView=view; } @Override public void detachView() { mMainView=null; } @Override public void searchUser(String loginName) { if(TextUtils.isEmpty(loginName.trim())){ MMainView. ShowErrorMessage (" please enter the legal login name "); return; } if (mModel! = null) {mModel. GetUser (new Subscriber () {@ Override public void onStart () {/ / to display the dialog box mMainView. ShowProgressDialog (); } @ Override public void onCompleted () {/ / request end, dialog disappear mMainView. HideProgressDialog (); } @ Override public void onError (Throwable e) {/ / the error mMainView. ShowErrorMessage (" search failure "); } @Override public void onNext(User user) { mMainView.showText(user); } },loginName); }}}Copy the code

public class MainModel implements BaseModel{ @Override public void getUser(Subscriber subscriber ,String loginName) { HttpMethods.getInstance().getUser(subscriber,loginName); }}Copy the code

The Model implementation class here is relatively simple and uses the wrapped HttpMethods methods directly. (Model can be understood as a warehouse manager, and our network can be understood as a large warehouse).

In MainPresenter we actually use the Model method, which is P — >M

Then use the Rxjava observer to observe the result, and then call the View method to refresh the interface, namely P — >V

If you go back and look at our MVP chart, is it the same? (For an MVP, try the Contract category.)