1. What is that?
MVP is a design pattern (framework), because its excellent decoupling function is widely used in Android project. It divides the application into Model-View-Presenter, which is called MVP for short.
- Model is responsible for data processing and storage, and callback data to Presenter
- Presenter is responsible for forwarding View layer requests (such as clicking, updating view data) to the corresponding Model, receiving callbacks and notifying the View layer to update the view.
- View (View) is only responsible for displaying data
- Contract (contract class) is only used to define the interface between View and Model for easy management and viewing.
The basic process of a simple view update
The order is according to (1), (3) and (4)
In View, we send a request to Presenter to update TextView.
2 Presenter receives the request and sends the request for String to the corresponding Model (it may take time to operate in the middle, so it may need a callback interface)
3. Successfully get the data and then send it to Presenter through the callback interface.
4 Presenter gets the data and triggers the View callback
5 Finally complete the view update of View.
From beginning to end, View only processes the user's request (updating TextView) and sends it to Presenter, then provides a callback for updating the view; Presenter only does forwarding, but does not process logic itself; model is responsible for providing information, including data processing.
Some versions of MVP may choose to put data processing into Presenter, and then the model has only one setter/getter function similar to JavaBean, but I think this process makes Presenter bloated, so I choose to put logical processing into Model. Either way can.
2. MVP Universal Framework
2.1 Control Layer
Contract doesn't have a very general framework, because each view and each model works differently. Here's an example from the figure above.
class DetailContract{ interface DetailView{ fun onChangeText(String) } interface DetailModel { fun getNowText(callBack: GetTextCallBack) } interface GetTextCallBack{ fun onSuccess(str:String) fun onFail(info:String) } }
2.2 Model level
Model also has no very general framework. Here's an example from the figure above.
class SampleModel: DetailContract.DetailModel{ override getNowText(callBack: GetTextCallBack){ val str = ... //These are the operations to get String if(str!=""){ callBack.onSuccess(str) }else{ callBake.onFail("Acquisition failure") } } }
The concrete Model class here implements the interface in the Contract contract class to facilitate our Presenter calls.
2.3 View level
View in Android generally includes two kinds, one is Activity, the other is Fragment, which only gives the encapsulation of Activity. Fragment is similar and needs to deal with some life cycle problems.
Activity:
abstract class BaseActivity<V,T:BasePresenter<V>>:Activity(){ val TAG:String = javaClass.simpleName protected lateinit var mPresenter: T lateinit var mContext: Context override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mContext = this //Initialize Presenter mPresenter = createPresenter() //Binding Presenter and View mPresenter.attachView(this as V) //Initialize layout initView(savedInstanceState) } /** * The method of initializing view that should be implemented by subclasses */ abstract fun initView(savedInstanceState: Bundle?) /** * Create the corresponding Presenter */ abstract fun createPresenter():T //Unbind override fun onDestroy() { super.onDestroy() mPresenter.detachView() } }
Base Activity is an abstract class, which should be inherited by all activities that join the MVP pattern. Generic V represents the view (i.e. itself), and T is the corresponding Presenter. The View layer holds references to the corresponding Presenter for sending messages.
2.4 Presenter layer
abstract class BasePresenter<T> { //Weak references to the View interface type prevent the view held from being destroyed, but the presenter still holds, resulting in memory leaks protected lateinit var mViewRef:Reference<T> //Binding View Reference fun attachView(view:T){ mViewRef = SoftReference<T>(view) } //Get the View reference for the current binding protected fun getView(): T? { return mViewRef.get() } //Is View Binded fun isViewAttached(): Boolean { return mViewRef != null&&mViewRef.get()!=null } //Remove references fun detachView(){ if (mViewRef != null){ mViewRef.clear() } } }
BasePresenter is an abstract class that should be inherited by all Presenters that join the MVP pattern.
Presenter holds a weak reference in the View layer, and includes four methods related to weak reference. They are binding the reference of View, getting the reference of the current View, deciding whether the View has been bound and removing the reference of View.
There is also a corresponding Model object in the specific Presenter. Presenter holds both View and Model so that it can forward information.
The input is the View interface type in Control because Presenter can only transmit information to view through the interface. Not a specific type.
These are some commonly used frameworks. Let's continue to deepen our understanding with real combat.
3. actual combat
This example is selected from the mid-term assessment of Hongyan Mobile Development Department, which is about a music App. Just analyze the playback page (because I made two pages)