There's a new way to write MVP again. I think it's very good this time. Ali's internal information

Basemvpvview is the basic View layer interface:

public interface BaseMvpView {
    void showError(String msg);

    void complete();

    void showProgressUI(boolean isShow);
} 

You can see that some public interface methods are defined. In fact, this interface may not be required, but it is generally written for convenience.

  • BasePresenter

BasePresenter is the basic BasePresenter, which is also used to implement some public Presenter interface methods:

public class BasePresenter <V> {

    protected Context mContext;
    protected V mView;

    protected void onCleared() {

    }

    public void attachView(Context context, V view) {
        this.mContext = context;
        this.mView = view;
    }

    public void detachView() {
        this.mView = null;
    }

    public boolean isAttachView() {
        return this.mView != null;
    }

    public void onCreatePresenter(@Nullable Bundle savedState) {

    }

    public void onDestroyPresenter() {
        this.mContext = null;
        detachView();
    }

    public void onSaveInstanceState(Bundle outState) {

    }
} 

It implements some public Presenter methods, such as attachView, detachView and isAttachView, which must be implemented because they are related to life cycle binding and can be used for resource assignment and release.

  • BaseMvpActivity

As we all know, this is the base class of Activity. Take a look at its implementation:

public abstract class BaseMvpActivity<P  extends BasePresenter> extends AppCompatActivity  implements BaseMvpView {

    private PresenterProviders mPresenterProviders;
    private PresenterDispatch mPresenterDispatch;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getContentView());
        mPresenterProviders = PresenterProviders.inject(this);
        mPresenterDispatch = new PresenterDispatch(mPresenterProviders);

        mPresenterDispatch.attachView(this, this);
        mPresenterDispatch.onCreatePresenter(savedInstanceState);
        init();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mPresenterDispatch.onSaveInstanceState(outState);
    }

    protected abstract int getContentView();

    public abstract void init();

    protected P getPresenter() {
        return mPresenterProviders.getPresenter(0);
    }

    public PresenterProviders getPresenterProviders() {
        return mPresenterProviders;
    }

    @Override
    public void showError(String msg) {

    }

    @Override
    public void complete() {

    }

    @Override
    public void showProgressUI(boolean isShow) {

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPresenterDispatch.detachView();
    }
} 

The generic P defined behind BaseMvpActivity is mainly used when using the getpresenter () method for a Presenter. The code is shown in the above example. Take a look at the implementation of getPresenter():

protected P getPresenter() {
    return mPresenterProviders.getPresenter(0);
} 

It just calls the PresenterProviders.getPresenter(int index) method.

Then BaseMvpActivity implements the basemvpvview interface and implements some public methods by default. When you inherit it, you can override them.

Mainly talk about PresenterProviders. This class is used to parse the annotations used and complete some public Presenter operations such as binding and unbinding View.

  1. First, call the inject method to instantiate and pass in the context parameter.
  2. By looking at the implementation of the inject, it calls the constructor, which then calls the resolveCreatePresenter and resolvePresenterVariable methods to resolve the annotation @ CreatePresenter and @ PresenterVariable.
public static PresenterProviders inject(Context context) {
    return new PresenterProviders(context);
}

private PresenterProviders(Context context) {
    mContext = checkContext(context);
    resolveCreatePresenter();
    resolvePresenterVariable();
} 

The following is a brief analysis of the specific implementation of PresenterProviders:

  1. For the knowledge of annotation, you can read this article. After reading it, you should understand: Deep understanding of Java annotation types (@ Annotation)

  2. PresenterStore class: the main function of this class is to store the Presenter instance, which is implemented by HashMap:

private static final String DEFAULT_KEY = "PresenterStore.DefaultKey";
private final HashMap<String, P> mMap = new HashMap<>();

public final void put(String key, P presenter) {
    P oldPresenter = mMap.put(DEFAULT_KEY + ":" + key, presenter);
    if (oldPresenter != null) {
        oldPresenter.onCleared();
    }
}

public final P get(String key) {
    return mMap.get(DEFAULT_KEY + ":" + key);
}

public final void clear() {
    for (P presenter : mMap.values()) {
        presenter.onCleared();
    }
    mMap.clear();
} 

Because one or more Presenter objects need to be processed, the purpose of this is to manage and find them uniformly.

  1. Then we go to the main PresenterProviders class. This class mainly looks at several methods. The first resolveCreatePresenter() method:
public <P extends BasePresenter> PresenterProviders resolveCreatePresenter() {
    CreatePresenter createPresenter = mContext.getClass().getAnnotation(CreatePresenter.class);
    if (createPresenter != null) {
        Class<P>[] classes = (Class<P>[]) createPresenter.presenter();
        for (Class<P> clazz : classes) {
            String canonicalName = clazz.getCanonicalName();
            try {
                mPresenterStore.put(canonicalName, clazz.newInstance());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
    return this;
} 

The resolveCreatePresenter() method is mainly used to parse the @ CreatePresenter annotation. The process is as follows: first obtain all the class object array classes defined on the annotation, then loop, take their canonicalName as the key, call the newInstance method, instantiate it and store it as the value in the HasMap mentioned above.

Next is the resolvePresenterVariable method:

public <P extends BasePresenter> PresenterProviders resolvePresenterVariable() {
    for (Field field : mContext.getClass().getDeclaredFields()) {
        //Get annotation on field
        Annotation[] anns = field.getDeclaredAnnotations();
        if (anns.length < 1) {
            continue;
        }
        if (anns[0] instanceof PresenterVariable) {
            String canonicalName = field.getType().getName();
            P presenterInstance = (P) mPresenterStore.get(canonicalName);
            if (presenterInstance != null) {
                try {
                    field.setAccessible(true);
                    field.set(mContext, presenterInstance);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    return this;
} 

The resolvePresenterVariable method is mainly used to find the corresponding instance in HashMap for the object marked with @ PresenterVariable annotation and assign a value. The process is as follows: first, get the fields of all variables on the class through getdeclaraedfields, and then judge that if the variable is marked with @ PresenterVariable annotation, take the Name corresponding to its Type. The value of this Name will be the same as the canonicalName, so you can use it as a key to find the corresponding instance in HashMap, After finding it, assign a value to the variable through the set method of Field.

There is also a class PresenterDispatch:

You can see that attachView, detachView and other operations are completed through it. This class is needed to isolate PresenterProviders and PresenterStore to avoid coupling.

public class PresenterDispatch {
    private PresenterProviders mProviders;

    public PresenterDispatch(PresenterProviders providers) {
        mProviders = providers;
    }

    public <P extends BasePresenter> void attachView(Context context, BaseContract.View view) {
        PresenterStore store = mProviders.getPresenterStore();
        HashMap<String, P> mMap = store.getMap();
        for (Map.Entry<String, P> entry : mMap.entrySet()) {
            P presenter = entry.getValue();
            if (presenter != null) {
                presenter.attachView(context, view);
            }
        }
    }

    public <P extends BasePresenter> void detachView() {
        PresenterStore store = mProviders.getPresenterStore();
        HashMap<String, P> mMap = store.getMap();
        for (Map.Entry<String, P> entry : mMap.entrySet()) {
            P presenter = entry.getValue();
            if (presenter != null) {
                presenter.detachView();
            }
        }
    }
    ...
} 

You can see that he gets the PresenterProviders object, then gets the HashMap that stores the Presenter instance, and then operates. Other public implementations can do the same.

The whole process is finished, isn't it very simple. In the actual application process, you can make corresponding modifications according to your own needs. If you like it, give it a Star. You are welcome to leave a message and put forward Issues and suggestions.

Interview review notes

This information will be published on blogs and forums since the spring recruit. Collect high-quality interview questions in Android Development on the website, and then find the best solution throughout the network. Each interview question is a 100% real question + the best answer. Package knowledge context + many details.
You can save the time of searching information on the Internet to learn, and you can also share it with your friends to learn together.
CodeChina open source project: Android learning notes summary + mobile architecture Video + big factory interview real questions + project actual combat source code

960 page Android Development Notes

1307 pages of Android development interview

It includes the questions asked in the interview of front-line Internet companies such as Tencent, Baidu, Xiaomi, Ali, LETV, meituan, 58, cheetah, 360, Sina and Sohu. Familiarity with the knowledge points listed in this article will greatly increase the probability of passing the first two rounds of technical interviews.

507 page Android development related source code analysis

As long as programmers, whether Java or Android, don't read the source code and only look at the API documents, they will just stay superficial, which is unfavorable to the establishment and completion of our knowledge system and the improvement of practical technology.

What can really exercise your ability is to read the source code directly, not only limited to reading the source code of major systems, but also various excellent open source libraries.


Questions asked in the interview of front-line Internet companies such as, Sina and Sohu. Familiarity with the knowledge points listed in this article will greatly increase the probability of passing the first two rounds of technical interviews.

[external chain picture transferring... (img-9bjdjPg2-1631094235036)]

507 page Android development related source code analysis

As long as programmers, whether Java or Android, don't read the source code and only look at the API documents, they will just stay superficial, which is unfavorable to the establishment and completion of our knowledge system and the improvement of practical technology.

What can really exercise your ability is to read the source code directly, not only limited to reading the source code of major systems, but also various excellent open source libraries.

[external chain picture transferring... (img-8pQFE6aR-1631094235037)]

Keywords: Java Android Design Pattern

Added by k.soule on Wed, 24 Nov 2021 02:49:22 +0200