People can, is to believe that can.

Speaking of MVP, everyone should be familiar with this design pattern, because of its height solution and other advantages, more and more projects use it. Advantages in, however, there are also shortcomings, one is a lot more, directly to project communication with P and V, then P hold V instance, hang out, but if the activity if there is no release of V, and the cause of memory had problems, and so many interface function, see a person dazzling, Also makes a lot of people in the use of this model when looking ahead.

Back to the topic, recently in the code refactoring, decided to adopt MVP mode for development. If we had simply developed using MVP without encapsulation, we would have had the same problems as above, with multiple and repetitive interfaces and classes. There are also problems with co-developing with others. It is important to encapsulate the MVP mode. Of course, there are a thousand Hamlets in a thousand people, here is my thinking, for your reference.

What is MVP mode

MVP mode is equivalent to adding a Presenter to MVC mode to process Model and logic, completely separate View and Model. In Android development, activity is only used to display interface and interaction, and activity does not participate in Model structure and logic.

Using MVP mode will make the code more interfaces but make the code logic more clear, especially when dealing with complex interface and logic, we can separate each business of the same activity into a Presenter, so that the code is clear, logical and convenient for us to expand. Of course, if our business logic itself is relatively simple, using the MVP model is not necessary. So we don’t need to use it just for the sake of using it, it’s still a business need.

In fact, in short: The View is the UI, the Model is the data processing, and persenter is their link.

Use the structure of MVP

Compare that to MVC

There are some drawbacks to the MVP model, the biggest of which is the rapid growth of classes, which can be a big drawback compared to MVC’s bloated and MVP’s high degree of decoupling

Packaging ideas

Introduction to the picture above:

Contract: The View interface, Model interface and request data callback of a functional module are defined in the Contract of the corresponding module, easy to manage.

ViewInterface: The View-layer interface that defines the UI operations in the view

ModelInterface: Model layer interface, which defines the data operation methods that model is responsible for, such as request interface, operation database, etc

CallbackInterface: callback after the operation data is completed in the Model layer

BasePersenter: parent class of Persenter, which is mainly used to obtain and destroy related views

View: View layer implementation class, mainly is the Activity or Fragment, responsible for UI display and event response

Model: The Model layer implements the class, which requests the corresponding interface or database based on the business and returns the result to the CallBack

Persenter: The Persenter layer class is responsible for business logic processing. The View passes the response to Persenter. Persenter calls the Model and returns the result to the View for presentation

Frame encapsulation

1. Presenter encapsulation

/** * Description: Presenter root parent class * Created by JIA on 2016/10/27. */ public abstract class BasePresenter<T> {// protected Reference<T> mViewRef; Public void attachView(T view) {mViewRef = new SoftReference<T>(view); } protected TgetView() {
        return mViewRef.get();
    }

    public boolean isViewAttached() {
        returnmViewRef ! = null && mViewRef.get() ! = null; } public voiddetachView() {
        if(mViewRef ! = null) { mViewRef.clear(); }}}Copy the code

Take a look at the base class:

Set the generic type T to the view associated with the presenter. A BasePresenter holds a soft reference to a View.

Pass the View object in the association method, and store it in the soft reference, and create the methods to get, cancel the association, and determine.

Soft references are used to prevent the view from being destroyed, but the presenter keeps it, causing a memory leak.

2. Encapsulation of view

View encapsulation, mainly BaseActivity and BaseFragment encapsulation.

2.1, BaseActivity

public abstract class BaseActivity<V, T extends BasePresenter<V>> extends FragmentActivity {

    public String TAG = getClass().getSimpleName() + ""; protected T mPresenter; public Context mContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); . initActivityView(savedInstanceState); mContext = BaseActivity.this; MPresenter = createPresenter(); // Presenter is bound to viewif(null ! = mPresenter) { mPresenter.attachView((V) this); } findViewById(); getData(); } /** * Protected abstract void initActivityView(Bundle savedInstanceState); /** * load the page element */ protected abstract void findViewById(); /** * Create Presenter object ** @return
     */
    protected abstract T createPresenter();

    protected abstract void getData();

    @Override
    protected void onDestroy() { super.onDestroy(); .if(null ! = mPresenter) { mPresenter.detachView(); }}}Copy the code

BaseActivity sets two generics, V and P, which, obviously, represent the corresponding View and Presenter, respectively.

It has a BasePresenter. In the onCreated method, use the createPresenter method to return a subclass of the BasePresenter, so we can use it.

The view object is created in onCreated, but the soft reference to the view inside it is still empty. When the view is associated with onResume, the presenter already has a soft reference to the view. Of course, you also need to disassociate in onDestroy.

As for the other encapsulation is no longer introduced, I believe you must have a better encapsulation method.

2.2 BaseFragment

public abstract class BaseFragment<V, T extends BasePresenter<V>> extends Fragment {

    public String TAG = getClass().getSimpleName() + "";

    private static final String STATE_SAVE_IS_HIDDEN = "STATE_SAVE_IS_HIDDEN"; protected T mPresenter; // Define a View to save the layout of the Fragment when it is created using the pump tool. */ @override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPresenter = createPresenter(); } @override public void onSaveInstanceState(Bundle outState) {outstate.putBoolean (STATE_SAVE_IS_HIDDEN, isHidden()); } /** * This method is used when creating the Fragment, */ @override public View onCreateView(LayoutInflater Inflater, Inflater) ViewGroup container, Bundle savedInstanceState) { view = initFragmentView(inflater);returnview; } /** * This method works after the view in the onCreateView method is created. FindViewById */ @Override public void onViewCreated(View View, Bundle savedInstanceState) { initFragmentChildView(view); } /** * this method is used after the Fragment has finished creating the Fragment, */ @override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); initFragmentData(savedInstanceState); } /** * Protected abstract View initFragmentView(LayoutInflater Inflater); /** ** @param view */ protected abstract void initFragmentChildView(view view); ** @param savedInstanceState */ protected abstract void initFragmentData(Bundle savedInstanceState); /** * create a Presenter object */ protected abstract T createPresenter(); @Override public voidonResume() {
        super.onResume();
        if(null ! = mPresenter) { mPresenter.attachView((V) this); } } @Override public voidonDestroy() {
        super.onDestroy();
        if(null ! = mPresenter) { mPresenter.detachView(); }}}Copy the code

BaseFragment is similar to BaseA and is no longer redundant.

3, Contract class

Contracts, as the name suggests, define specifications that define functionality and templates.

Define the interface to the View and the interface to the Model in the contract class. Since the Model uses callbacks to return data to the Presenter, the corresponding callbacks need to be defined in the contract class.

Let’s see an example.

In actual combat

Here we take the login function module as an example:

1. Contracts

/** * Description: * Created by Jia on 2017/12/20. */ public class LoginContract {public interface LoginView{void onCheckFormatSuccess(); void onCheckFormatFail(String info); void onLoginSuccess(Login login); void onLoginFail(String errorInfo); } public interface LoginModel{ void login(String name,String password,LoginCallBack callBack); } public interface LoginCallBack{ void onSuccess(Login login); void onFail(String errorInfo); }}Copy the code

The view interface, the Model interface, and the corresponding callback for the login page are defined here.

In view, only methods related to THE UI display are defined, such as checking the success of account password format (failed), login success (failed), and so on.

The Model takes care of the data requests, so only the login method is defined in the interface.

The callback defines how the login succeeds or fails.

2. Model implementation class

/** * Description: * Created by JIA on 2017/12/20. */ public class implements loginContract. LoginModel {/** * Implements loginContract. LoginModel {/** * implements @param name * @param password * @param callBack */ @Override public void login(String name, String password, final LoginContract.LoginCallBack callBack) { LoginNetUtils.getInstance().login(name, password, new BaseSubscriber<Login>() { @Override public void onSuccess(Login login) { callBack.onSuccess(login); } @Override public void onFail(String info) { callBack.onFail(info); }}); }}Copy the code

Create a Model implementation class, override its login method, and leave the login interface to the callback.

3, Presenter

/** * Description: * Created by JIA on 2017/12/20. */ public class LoginPresenter extends BasePresenter< loginContract. LoginView> {private LoginModelImpl Model; publicLoginPresenter() { model = new LoginModelImpl(); } /** * Check the format ** @param name * @param password */ public void checkFormat(String name, String password) {if (TextUtils.isEmpty(name)) {
            getView().onCheckFormatFail("Please enter your user name.");
        } else if (TextUtils.isEmpty(password)) {
            getView().onCheckFormatFail("Please enter your password");
        } else if (password.length() < 6 || password.length() > 18) {
            getView().onCheckFormatFail("Password format is incorrect");
        } else{ getView().onCheckFormatSuccess(); login(name, password); Public void login(String name, String password) {model.login(name, String password) {model.login(name, String password, String password); password, new LoginContract.LoginCallBack() { @Override public void onSuccess(Login login) { getView().onLoginSuccess(login); } @Override public void onFail(String errorInfo) { getView().onLoginFail(errorInfo); }}); }}Copy the code

LoginPresenter integrates with BasePresenter, passing in LoginView as generic T.

Internally holds Model implementation class objects.

Create two methods, one for checking the format and one for logging in. The two methods are business processing.

For example, in the login method, the data is obtained in the callback after the login return, and some logic judgments can be made to hand the results to the corresponding method of the view.

Note that you can use the getView() method here, because in the superclass getView method directly returns the corresponding view instance.

4, the View

Public class extends BaseActivity< loginContract. LoginView, LoginPresenter> implements LoginContract.LoginView, View.OnClickListener { ... @Override protected void initActivityView(Bundle savedInstanceState) {setContentView(R.layout.activity_login);

    }

    @Override
    protected void findViewById() {... } @Override protected LoginPresentercreatePresenter() {
        return new LoginPresenter();
    }

    @Override
    protected void getData() {
    }

    @Override
    public void onCheckFormatSuccess() { loading.show(); } @Override public void onCheckFormatFail(String info) { RxToast.error(mContext, info).show(); } @Override public void onLoginSuccess(Login login) { ... } @Override public void onLoginFail(String errorInfo) { ... } @Override public void onClick(View view) { ... }... }Copy the code

The LoginActivity is the view of the login module, which integrates BaseActivity, passing in the view and Presenter generics.

Implement the LoginView interface and override the UI methods defined by the interface.

Create a LoginPresenter object in the createPresenter method and return it. This allows you to manipulate the logic directly using mPresenter.

Take a look at the event flow and data flow of the entire functional module

Roughly so, there are insufficient places we give more advice. ^_^

For more exciting content, follow my wechat official account — Android Motor vehicle