Use of Android MVP framework MVPro and source code analysis

Source: Internet
Author: User

Use of Android MVP framework MVPro and source code analysis

Recently I have read two articles about how to implement MVP in Android, a new idea about how to implement MVP mode in android, and how to develop Android applications using MVP architecture.
The two articles share the same idea, namely, using Activity and Fragment as Presenter. This method is different from the mainstream MVP method, but it solves the problems brought about by the Activity lifecycle well, in addition, I think it makes MVP implementation easier.

So the question is, how can we not implement our MVP with such a good idea? So I spent one night working out a small MVP framework-MVPro

MVPro Introduction

The implementation of MVPro is very simple. The idea is the same as described in the previous two articles. Activity and Fragment are both used as Presenter. First, a figure is given to explain the principle of MVPro,

Created with Rapha limit l 2.1.0 Presenter Presenter View View OnCreate Create BindPresenter Create Created SetContentView BindEvent Created

Presenter is our Activity or Fragment. What about View? To put it bluntly, we extract the View operation-related code from the Activity and Fragment. The idea is simple and clear, next we will take a simple demo to learn more about the use of MVPro.

MVPro usage

MVPro regards Activity as a Presenter, so the main line of our code should be Presenter. First, we should use the Presenter code,

public class MainActivity extends ActivityPresenterImpl
  
           implements AdapterView.OnItemClickListener, View.OnClickListener {    @Override    public void create(Bundle savedInstance) {    }    @Override    public void created(Bundle savedInstance) {    }    @Override    public void onItemClick(AdapterView
    parent, View view, int position, long id) {        mView.toast(position);    }    @Override    public void onClick(View v) {        if(v.getId() == R.id.newdata) newData();        else getData();    }    private void newData() {        new MainBiz().data(new MainBiz.Callback>() {            @Override            public void callback(ArrayList
   
     data) {                mView.setData(data);            }        });    }    private void getData() {        new MainBiz().data(new MainBiz.Callback>() {            @Override            public void callback(ArrayList
    
      data) {                mView.addData(data);            }        });    }}
    
   
  

MainActivity inherits from the ActivityPresenterImpl class, and there is no Code related to the Activity lifecycle in the Code. The two methods create and created are our only focus, but they must not be rewritten, both methods are provided by the Presenter. The difference between the two methods is that create is called before setContentView, while created is called after setContentView.
We can guess the remaining several methods are all initiated from the View layer, so let's take a look at how to write the View layer. From the generics implemented by MainActivity, we can see that the corresponding View layer code is in DataListView.

/** * Created by qibin on 2015/11/15. */public class DataListView extends ViewImpl {    private Button mButton1, mButton2;    private ListView mListView;    private ArrayAdapter
  
    mAdapter;    @Override    public void created() {        mButton1 = findViewById(R.id.newdata);        mButton2 = findViewById(R.id.adddata);        mListView = findViewById(R.id.list);    }    @Override    public void bindEvent() {        EventHelper.click(mPresenter, mButton1, mButton2);        EventHelper.itemClick(mPresenter, mListView);    }    @Override    public int getLayoutId() {        return R.layout.list_layout;    }    public void setData(ArrayList
   
     datas) {        mAdapter = new ArrayAdapter
    
     (mRootView.getContext(),                android.R.layout.simple_list_item_1, datas);        mListView.setAdapter(mAdapter);    }    public void addData(ArrayList
     
       datas) {        mAdapter.addAll(datas);    }    public void toast(int position) {        Toast.makeText(mRootView.getContext(),                mAdapter.getItem(position), Toast.LENGTH_SHORT).show();    }}
     
    
   
  

In the View layer, we do not care about how the layout file is set to Activity. We only return the layout file we want to use in getLayoutId, and created to obtain the required control,
However, we also rewrite a bindEvent method. In this method, we bind events to the control. Note that MVPro wants all events to be implements on the Presenter, because EventHelper
Provides Presenter-based event listening.

OK, the use of MVPro is so simple, but I believe many people are still confused, so we will go deep into the source code to understand the implementation process of MVPro.

MVPro source code

First, we need to start with Presenter. The source of Presenter is an interface, which defines the required methods of Presenter,

/*** Root interface of Presenter * Created by qibin on. */public interface IPresenter
  
   
{/*** Obtain the generic type of the current presenter * @ return */Class
   
    
GetViewClass ();/*** you can perform some operations on this method before initialization of View */void create (Bundle savedInstance ); /*** call View after initialization */void created (Bundle savedInstance );}
   
  

There are only three methods. getViewClass is the class that gets the corresponding View layer class. For example, in the demo above, it corresponds to DataListView, create and created are two extension methods called before and after onCreate setContentView. Next, let's take a look at the ActivityPresenterImpl Code inherited by MainActivity above,

/*** Use Activity as the base class of Presenter * Created by qibin on. */public class ActivityPresenterImpl
  
   
Extends Activity implements IPresenter
   
    
{Protected T mView; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); create (savedInstanceState); try {mView = getViewClass (). newInstance (); mView. bindPresenter (this); setContentView (mView. create (getLayoutInflater (), null); mView. bindEvent (); created (savedInstanceState);} catch (Exception e) {throw new RuntimeException (e. getMessage () ;}@ Override public Class
    
     
GetViewClass () {return GenericHelper. getViewClass (getClass () ;}@ Override public void create (Bundle savedInstance) {}@ Override public void created (Bundle savedInstance ){}}
    
   
  

I guess many people think it should be complicated before they see the ActivityPresenterImpl source code, but after reading it, they may not be able to say: Nima, so little! There are indeed few codes, and they are basically concentrated in onCreate. However, before reading onCreate, Let's first look at the getViewClass method, which implements self-IPresenter and only has one line of code, it is used to obtain the View layer class specified by the current Presenter generic type, corresponding to DataListView in the demo above.

Next we will return to onCreate. In onCreate, we first call the create method, so that we can execute some code before setContentView, such as setting a title-less object.
Then, the class of the View layer is obtained through getViewClass and its object mView is obtained through reflection. The next step is related to this mView.
Call the mView. bindPresenter method to associate the current Presenter to the current View layer.
Call the mView. create method to generate the View object corresponding to the layout file, and set the layout file through setContentView.
Call the mView. bindEvent method. In this method, we can set event listening for some controls.
Finally, we call the created method to write the code after the control Initialization is completed in development.

OK, the Presenter code is very simple. It mainly involves some procedural things. Let's look at how the code at the View layer is implemented. Or from the interface -- IView,

/*** View layer Root Interface * Created by qibin on. */public interface IView {/*** generate the root layout required for setContentView generation according to the {@ link getLayoutId} Method * @ param inflater * @ param container * @ return */View create (layoutInflater inflater, viewGroup container);/*** call */void created () after onCreate of Activity is completed (); /*** return the id of layout required by the current view * @ return */int getLayoutId ();/*** obtain view by id * @ param
  
   
* @ Return */
   
    
V findViewById (int id);/*** bind Presenter * @ param presenter */void bindPresenter (IPresenter presenter);/*** {@ link created, you can call {@ link org. loader. helper. eventHelper. click. loader. helper. eventHelper. click (IPresenter presenter, View... views)} * method and let your Presenter implement the corresponding interface. */Void bindEvent ();}
   
  

There are more methods defined in the IView interface. Let's talk about the reasons for the existence of these methods one by one.
The create method generates layout Objects Based on the provided layout id. The preceding setContentView parameter of Presenter is the return value.
Created is called after the inflater layout is complete for some operations.
GetLayoutId needs to be implemented and the id of the layout file is returned.
FindViewById provides a generic query control method. With this method, we no longer need to convert data types.
BindPresenter is bound to the corresponding Presenter.
BindEvent we need to implement this method to set listening for the control.

OK. After introducing these methods, let's take a look at what the base class of the View layer has done.

/*** View layer base class * Created by qibin on. */public abstract class ViewImpl implements IView {/*** create method generated view */protected View mRootView;/*** bind presenter */protected IPresenter mPresenter; @ Override public View create (LayoutInflater inflater, ViewGroup container) {mRootView = inflater. inflate (getLayoutId (), container, false); created (); return mRootView;} @ Override public
  
   
V findViewById (int id) {return (V) mRootView. findViewById (id) ;}@ Override public void created () {}@ Override public void bindPresenter (IPresenter presenter) {mPresenter = presenter ;}@ Override public void bindEvent (){}}
  

In the create method, we use LayoutInflater to generate a View object and return it to the Presenter for setContentView. before returning it, we also call the created method, in the project, we can find the required controls in this method.
The created and bindEvent methods are empty implementations here, so that we do not need to implement these two methods at any time in our own code.

OK, it's very simple. This is the code of MVPro. We have analyzed the whole process. What about the Model layer? We haven't seen any code about the Model layer yet! MVPro does not care about how your business layer is implemented. You can use the architecture of the business layer code that you are currently using without affecting MVP.

Finally, let's take a look at how EventHelper sets event listening.

public class EventHelper {    public static void click(IPresenter li, View ...views) {        if(!(li instanceof View.OnClickListener)) return;        click((View.OnClickListener) li, views);    }    public static void click(View.OnClickListener li, View ...views) {        if(views == null || views.length == 0) return;        for(View v : views) v.setOnClickListener(li);    }    ...}

Here we take the click event as an example. We can see that our parameter is of the IPresenter type, and it determines whether the Presenter you passed implements the View. if the OnClickListener interface is implemented, it will be used for forced type conversion. Here we can also see that in order to minimize the Code Coupling Between Our Presenter and the View layer, MVPro does not use generics, and it is not recommended to pass the OnClickListener object from the Presenter. Instead, we recommend that our Presenter directly implement the OnClickListener interface, eventHelper automatically checks the type and sets the listener.

Well, here, we have another helper class that does not see the implementation, that is, the helper class that gets the generic type.

/** * Created by qibin on 2015/11/15. */public class GenericHelper {    public static 
  
    Class
   
     getViewClass(Class
     klass) {        Type type = klass.getGenericSuperclass();        if(type == null || !(type instanceof ParameterizedType)) return null;        ParameterizedType parameterizedType = (ParameterizedType) type;        Type[] types = parameterizedType.getActualTypeArguments();        if(types == null || types.length == 0) return null;        return (Class
    
     ) types[0];    }}
    
   
  

There is only one method in this class, but most people may be unfamiliar with the code here. What we do here is very direct, that is, according to the class we provide, to obtain the generic type implemented by this class. For example, the following code obtains java. lang. string,

class Child extends Super
  
    {}
  

OK, the article is coming to an end. The overall implementation of MVPro is still very simple. If you have any questions or feel that MVPro needs some improvements, you can leave a message for me below, I will constantly improve this small framework.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.