Original statement: This article is an original article, it is strictly prohibited to reprint without the consent of the blogger.

Abstract: In the last article we discussed how to encapsulate common data requests and optimize the MVP pattern. In actual projects, in addition to ordinary data, we generally have data of column phenotype. The main difference between the data of column phenotype and ordinary data is that the data of column phenotype needs to be obtained in pages. In a real project, we usually send the page number and the number of data items on a page to the server to fetch paging data. By encapsulating the presenters of a list of phenotypes, we can automatically handle the time required to process most of the typed phenotype data.

Presenter base class that encapsulates the column phenotype

As we learned in the previous article, the main role of the Model in MVP mode is to make a request to the server and then send the data returned by the server to the Presenter for processing. Therefore, when encapsulating the column phenotype Presenter, BaseModel mentioned in the previous chapter is directly used to obtain data and callback data. One thing to note here is that I made some changes to some of the class names while developing the framework, which is based on the complete framework provided at the end of the series.

Let’s take a look at the interface and implementation of a column phenotype Presenter

Public interface IBasePaginationPresenter extends IBasePresenter {void refresh(Params Params); // Load the next page of data void loading(); / @method: refreshAssignPage @author create by Tang @date Date 16/10/19 am 11:07 @Description: @param index Specifies the location of the data to be refreshed. / void refreshIndexPage(int index); Void setCount(int count); void accessServer(); }Copy the code

As you can see from the code above, the IBasePaginationPresenter interface is an extension of IBasePresenter, which extends methods for handling column phenotype data.

/** * @className: BasePaginationPresenter * @author create by Tang * @date date 16/9/29 2:14 PM * @description: * @params: request parameter class (Params in HTTP) * @bean: Returns the data item entity class of the queue (the entity class in the bean) */ public Abstract class BasePaginationPresenter implements IBasePaginationPresenter {public abstract void serverResponse(List list); private IMvpListView baseView; private IBaseModel baseModel; private Params mParams; Private int mCount = ServerManager.count; private int mCount = serverManager.count; Private int mIndex = -1; private int mIndex = -1; // Page number to refresh (according to mIndex) private int mPage; private List dataList = new ArrayList<>(); private Class clazz; /** * @method: BasePaginationPresenter * @author create by Tang * @date date 16/10/20 10:18 am * @description: Constructor * @param clazz Type of queue parameter item, Cannot be null */ protected BasePaginationPresenter(@nonnull IMvpListView baseView, @NonNull Class clazz){ this.baseView = baseView; this.baseModel = new BaseModel(this); this.clazz = clazz; } @Override public void refresh(Params params) { this.mParams = params; dataList.clear(); loading(); } @Override public void loading() { if (mParams == null){ mParams = (Params) new BasePaginationParams(); mParams.count = mCount; Mparams.page = (int) math.ceil ((double) dataList. Size () 1.0 / mCount) + 1; mparams.page = (int) math.ceil (double) dataList. }else { mParams.count = mCount; Mparams.page = (int) math.ceil ((double) dataList. Size () 1.0 / mCount) + 1; mparams.page = (int) math.ceil (double) dataList. } accessServer(); } @override public void refreshIndexPage(int index) {if (index > dataList. Size ()){// If (index > dataList. If the table below is 0, mPage = index/mCount; if the table below is 0, mPage = index/mCount; / mIndex = index; mPage = index / mCount + 1; if (mParams == null){ mParams = (Params) new BasePaginationParams(); mParams.count = mCount; mParams.page = mPage; }else { mParams.count = mCount; mParams.page = mPage; } } accessServer(); } @Override public void setCount(int count) { this.mCount = count; } @Override public Map getParams() { if (mParams ! = null){ LogUtil.d(getClass(), "getParams: " + mParams.toString()); return mParams.toMap(); }else { return null; } } @Override public IBaseModel getModel(){ return baseModel; } @Override public void accessServer() { baseView.showProgress(true); /** * cancelRequest(); /** * cancelRequest(); baseModel.sendRequestToServer(); } /** * @method: accessServer * @author create by Tang * @date date 16/10/19 PM 3:56 * @description: * Deprecate this method when fetching data in queue type, * the parameter is passed in via the Refresh(Params Params) method */ @deprecated @override public void accessServer(Params Params) {} @override public void accessSucceed(JSONObject response) { String responseStr = String.valueOf(response); baseView.showProgress(false); ParameterizedType parameterized = ClassTypeUtil.type(BasePaginationResponse.class , ClassTypeUtil.type(List.class,clazz)); Type type = $Gson$Types.canonicalize(parameterized); BasePaginationResponse> mResponse = new Gson().fromJson(responseStr, type); if (mResponse.errNum == 0){ if (mIndex < 0){ dataList.addAll(mResponse.data); baseView.isNextPage(mResponse.nextPage); }else {int start = (mpage-1) mCount; ListUtils.replaceAssign(start,dataList,mResponse.data); mIndex = -1; } serverResponse(dataList); }else { baseView.showServerError(mResponse.errNum,mResponse.errMsg); } } @Override public void volleyError(int errorCode, String errorDesc, String ApiInterface) { baseView.showNetworkError(errorCode,errorDesc,ApiInterface); } @Override public void cancelRequest() { baseModel.cancelRequest(); }}Copy the code

The code is very simple, in BasePaginationPresenter IBasePresenter interface implementation and BasePresenter in the same, I will focus on several of these methods.

  1. AccessServer () : This method is responsible for notifying the Model layer of the request to the server because the request parameters are specified by therefresh(Params params)So you can see that accessServer(Params Params) has been deprecated.
  2. Refresh (Params Params) : This method refreshes the list data. The loading method is used to fetch data from the server. The dataList method is used to store fetched data. Before calling the dataList method, you need to call the List clear() method to clear the cache.
  3. Loading () : Data loading method, notifying the Model layer to initiate a data loading request to the server. This method realizes automatic calculation of paging data.
  4. RefreshIndexPage (): Local refresh method, called after calculating the page to be refreshed based on the position of the data item to be refreshedaccessServer ()Method to refresh a specific page.
  5. SetCount (int count): Sets the amount of data to be fetched at a time. Count has a default value. You can call this method setting if you need to reset the value. This method can only be called once in presenter (multiple calls will result in data retrieval errors).

IMvpListView

public interface IMvpListView extends IBaseMvpView { /** * @Method: IsNextPage * @author create by Tang * @date Date 16/10/20 5:56 PM * @description: */ nextPage (int nextPage); */ nextPage (int nextPage); }Copy the code

This interface is a View interface designed for column phenotype data, adding an isNextPage(int nextPage) method. The main function is to determine whether there is a next page, and this method needs to be designed according to the business. The main purpose of this method is to make a judgment before using pull-up loading. If the server has unloaded data, turn on the pull-up load function in the View layer, otherwise turn off the pull-up load function.

This section summary

With the groundwork laid in the previous article, this is the end of the introduction to BasePaginationPresenter. Let’s look at a concrete implementation example.

Practical examples

Here, the author uses the baidu API Store interface to test. Because the design of the interfaces on Baidu API Store is different, readers should use the framework according to the actual situation. If you have any questions, please leave a comment below the blog. I will try my best to answer the questions raised. The main points to note in practice are: BaseResponse and BasePaginationResponse are the data parsing classes. When I tested baidu’s interface, I found that Baidu’s interface actually does not support POST requests. So we can only follow baidu’s method in the interface path with the parameters passed by the GET method to initiate a request. Preparation: Apply for a Baidu API key and set the request headers in Volley’s getHeaders() method. As shown below.

@Override public Map getHeaders() throws AuthFailureError { Map header = new HashMap<>(); // Set the API store request header. Put ("apikey",""); return header; }Copy the code

Well, yes, I found that empty apiKey does not affect the use of the interface. So let’s leave it empty.

Baidu API server address is “http://apis.baidu.com

Baidu Weather Interface

This interface is an interface to query the weather of a city by its name. The interface is defined as:

public static final String WEATER = "/apistore/weatherservice/cityname? Cityname = "in Beijing;

IWeatherView

public interface IWeatherView extends IMvpView {  
  
    void showWeatherView(WeatherBean data);  
}Copy the code

IWeatherView has only one showWeatherView() method, which passes the Presenter’s data to the View layer.

WeatherBean

Weather entities

Public class WeatherBean {// city public String city; // Public String pinyin; Public String cityCode; // Date public String date; Public String time; Public String postCode; // longitude public String longitude; // dimension public String latitude; Public String altitude; Public String weather; Public String temp; // Minimum temperature public String l_tmp; Public String h_tmp; Public String WD; Public String WS; Public String sunrise; // Sunset time public String sunset; }Copy the code

WeatherPresenter

public class WeatherPresenter extends BasePresenter { private IWeatherView weatherView; public WeatherPresenter(IWeatherView weatherView) { super(weatherView,WeatherBean.class); this.weatherView = weatherView; getModel().setApiInterface(ApiInterface.WEATER); } @Override public void serverResponse(WeatherBean data) { weatherView.showWeatherView(data); }}Copy the code

We can see that the implementation of WeatherPresenter is very simple. According to our previous theory, we only need to write WeatherPresenter to obtain the weather data of Beijing. So let’s test that out.

Use WeatherPresenter in your Activity

First implement the IWeatherView interface in the required Activity (View layer) :

public class MainActivity extends AppCompatActivity implements IWeatherView{  
   @Override  
   public void showWeatherView(WeatherBean data) {  
       Toast.makeText(this,data.weather,Toast.LENGTHSHORT).show();  
        }  
}`
`Copy the code

The implementation of the interface is simple, simply displaying the weather through Toast.

Here’s a look at the use of WeatherPresenter:

WeatherPresenter weatherPresenter = new WeatherPresenter(this); weatherBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { WeatherParams params = new WeatherParams(); Cityname = "cityname "; weatherPresenter.accessServer(params); }});Copy the code

Let’s take a look at the results:

Note that baidu’s API does not support POST requests, so when we use Baidu’s API, we need to invoke the interface with a GET request according to the method provided by Baidu, so the WeatherParams parameter in the above example is invalid. This is just to let the reader know that if the interface supports POST requests, this method can be used to make requests to the server, which is more flexible and easy to use.

Baidu glutinous rice classification interface

This is an interface provided by Baidu API Store to get 6 baidu glutinous rice categories (not found on the API store, but still available).

The interface address: public static final String NUO_MI_CATEGOR = “/ baidunuomi/openapi/categories”;

INuoMiCategoryListView

interface INuoMiCategoryListView extends IMvpListView {

 void showNuoMiCategoryView(List nuoMiCategoryList);  
}Copy the code

The INuoMiCategoryListView interface is also simpler, passing the list of callbacks to the View layer. (The business logic here is simple, so it is passed to the View layer without any processing. Depending on the actual situation, you can define multiple methods.

NuoMiCategoryPresenter

public class NuoMiCategoryPresenter extends BasePaginationPresenter {  
  
    private INuoMiCategoryListView nuoMiCategoryView;  
  
    public NuoMiCategoryPresenter(INuoMiCategoryListView nuoMiCategoryView) {  
        super(nuoMiCategoryView,NuoMiCategoryBean.class);  
        this.nuoMiCategoryView = nuoMiCategoryView;  
        getModel().setApiInterface(NUOMICATEGOR);  
    }  
  
  
    @Override  
    public void serverResponse(List list) {  
        nuoMiCategoryView.showNuoMiCategoryView(list);  
    }  
}`
`Copy the code

NuoMiCategoryPresenter is easy to implement. NuoMiCategoryPresenter can refresh list data, load next page, etc. As the classification interface of Baidu nuomi is only one page, so we will not load the data of the next page for any discussion. Let’s look at NuoMiCategoryPresenter in action.

Use NuoMiCategoryPresenter in your Activity

The first step is to implement the INuoMiCategoryView interface in the Activity (View layer)

@override public void showNuoMiCategoryView(List nuoMiCategoryList) {toast.maketext (this," " + nuoMiCategoryList.get(0).catname,Toast.LENGTHSHORT).show(); } ` `Copy the code

For simplicity, the showNuoMiCategoryView(List\ nuoMiCategoryList) method uses Toast to display the name of the first category.

With the INuoMiCategoryView interface implemented, let’s try using NuoMiCategoryPresenter in an Activity to retrieve classified data.

nuoMiCategoryPresenter = new NuoMiCategoryPresenter(this); nuoMiCategoryBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { nuoMiCategoryPresenter.accessServer(); }});Copy the code

Let’s take a look at the results:

summary

The View layer interface for calling back data is derived from the IBaseMvpView interface, and there are three methods in the View layer (progress bar and error handling). If we do not encapsulate the processing of these methods, then every IView interface that implements callback data will need to manually implement these three methods again. So in future articles I’ll show you how to encapsulate some basic events by designing BaseActivity and BaseListActivity (Fragment). To optimize the project and further reduce the amount of code we have to write. The address of the project code is: github.com/DobbyTang/m… . The previous chapter and this chapter’s test demo were implemented in MainActivity, and the next chapter will parse the project’s directory in detail. Interested students are welcome to pay attention to this project, because the author is poor in writing, so the progress of the article will be greatly behind the project progress. The Activity and Fragmen base classes are complete, so you can check them out for yourself. If you don’t understand, please follow the blog, I will update the next chapter as soon as possible. Easter Egg: At the end of this series, I will use this framework to implement a small APP that will not be too complex, but will try to capture as much of what I have covered in this series.