MVP
What is MVP?
Look at the MVC architectural pattern before you get to the MVP.
MVC consists of three parts: 1. View, that is, each control in the View; 2. Controller, i.e. Activity, Fragment; 3. Data source.
However, it can be found in daily development that the control of the View layer is also in the Activity. At this time, when the Model layer is introduced to obtain the data source and then interacts with the Controller layer, it is not difficult to find that the three LAYERS of MVC have a holding relationship with each other, resulting in serious coupling.
The MVP architecture is to move the control layer down, the View layer acts as the existence of Activity and Fragment, the Model layer remains unchanged as the existence of the data source acquisition layer, and the communication between View and Model layer is completed by middleman Presenter data transfer. In this way, decoupling is achieved.
The way to communicate is to hold each other, but the middleman holds the View layer using weak references to ensure that the View is released in time.
A memory leak
The idea of decoupling has been expressed above, but there is another point behind decoupling that we are very concerned about — memory leaks. This small module can be divided into two questions: 1. What is a memory leak? ; 2. Can the MVP framework help us solve memory leaks?
What is a memory leak?
This is an old cliche, simply saying that something that was supposed to be released didn’t end up being released, and the cause of the problem could be a variable, a task, etc.
Can the MVP framework help us solve the memory leak problem?
Can the MVP framework help us solve the memory leak problem in the View layer? ** If you use the title question, which is actually a false proposition,
Does that solve this problem? This can be verified directly in a very simple way. Here is an example of code for a simple asynchronous thread to delay a task.
new Thread(new Runnable() {
@Override
public void run(a) {
SystemClock.sleep(200000);
}
}).start();
Copy the code
Integrated with Android StudioProfilerAbility to analyze memory information directly at run time.
There is a red – boxed button that, when clicked, prints out memory allocations over time. You can also click to analyze a point in time.
There are two pieces of information to pay attention to: the memory size occupied by the View layer, Prensenter layer and Model layer.
- The View layer
- Presenter layer and Model layer
As asynchronous threads are enabled in the Presenter layer, the View layer consumes much more memory than the Presenter and Model layers. If I had to choose the memory leak class, the final choice would be the one with less tendency, and MVP provides us with choice space, which is also a big benefit of MVP architecture.
Here, too, comes the headline conclusion that the MVP architecture mitigates the memory leak problem, but does not solve it.
Hand off an MVP structure
In MVP architecture, we have two code styles, M layer or P layer to do the complex logic, and one layer to do the complex logic. I prefer M layer to do these things.
M-V-P
The Presenter layer acts as a middleman and communicates with both the Model layer and the View layer, so it needs to hold both. In addition, the Presenter layer does not leak memory when the View layer is destroyed. The View layer reference methods are written as weak references.
abstract class BaseMvpPresenter<V: IMvpView, M: IMvpModel> : IMvpPresenter {
private var vWeakReference: WeakReference<V>? = null
protected val model: M by lazy { createModel() }
override fun bindView(mvpView: IMvpView) {
vWeakReference = WeakReference(mvpView as V)
}
override fun unBindView(a) {
if(vWeakReference ! =null) { vWeakReference? .clear() vWeakReference =null}}fun getView(a): V? = vWeakReference? .get(a)abstract fun createModel(a): M
}
Copy the code
Then there is the Model layer, which is the existence of data sources, and the methods of obtaining data sources are user-defined. Here, the Model layer only needs to reserve capabilities on the premise of holding the Presenter layer.
abstract class BaseMvpModel<P: IMvpPresenter> (val p: P): IMvpModel
Copy the code
Finally, there is the View layer, which is more specific to activities and fragments. A topic that cannot be avoided is holding. The View layer also needs to hold the Presenter layer first, which has the following initial code.
abstract class BaseMvpActivity<P : BaseMvpPresenter<*, *> > :AppCompatActivity(), IMvpView {
protected var p: P? = null
abstract fun getPresenter(a): P
}
Copy the code
But one question to consider is when should activities and fragments communicate with the Presenter layer? In order to accommodate life-cycle changes, the last natural consideration is in the onCreate() and onDestroy() methods of the Activity, and onAttach() and onDetach() methods of the Fragment.
abstract class BaseMvpActivity<P : BaseMvpPresenter<*, *> > :AppCompatActivity(), IMvpView {
protected var p: P? = null
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState) p = getPresenter() p? .bindView(this)}override fun onDestroy(a) {
super.onDestroy() p? .unBindView() }abstract fun getPresenter(a): P
}
Copy the code
abstract class BaseMvpFragment<P : BaseMvpPresenter<*, *> > :Fragment(), IMvpView {
protected var p: P? = null
override fun onAttach(context: Context) {
super.onAttach(context) p = getPresenter() p? .bindView(this)}override fun onDetach(a) {
super.onDetach() p? .unBindView() }abstract fun getPresenter(a): P
}
Copy the code
After completing the above steps, you have actually completed the construction of the entire framework, but if you inherit directly to play the framework, does it feel that there is something missing? Communication.
Establish communication
On top of all this code, the Model, Presenter, and View layers have already done the most basic thing, which is hold. But communication must need to hold, hold may not be able to communicate. Obviously, with the existing code base, communication infrastructure is a top priority.
This gives rise to the new communication layer Contract (TCP/UDP), which gives rise to an interface class between the different layers, which is responsible for the communication of the MVP layer 3. Here is an example of a protocol layer:
interface MainContract {
interface Model {
fun execute(a)
}
interface View<T: IMvpModel> {
fun handleResponse(data: T)
}
interface Presenter<T: IMvpModel> {
fun request(a)
fun response(data: T)}}Copy the code
By introducing these interfaces at different levels and implementing them, you end up with a complete MVP architecture.
MVVM
MVVM architecture is similar to MVP architecture in general, but the ViewModel layer and View layer are two-way communication, using DataBinding capabilities, so that the generation of ViewModel and binding to the View layer are completely completed by the system directly to simplify the development process. But when it comes to design, MVP is better for understanding the overall architecture.
An introduction to the MVVM
- Ability to introduce
android {
dataBinding {
enabled true
}
}
Copy the code
Developers programming with Kotlin need to introduce Kotlin-kapt
- use
The use of aspects can be divided into two small parts: layout use and binding use
- The layout to use
In the layout use and the usual XML writing will have a certain difference **, need to use the first layer of the package **, and the code writing can be divided into data area and layout area two parts. The layout area should be consistent with the usual writing method, focusing on the data area, which needs to be wrapped in the first layer to mark the data area. It is the definition of variables, in which the label is the name of the variable and the label is the type of the variable.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="user"
type="com.clericyi.android.helper.LoginModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.responseCode}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Copy the code
- Binding USES
After completing the layout Binding, Sync is required, which implements the same set of capabilities as ButterKnife and generates a new Binding file, but this Binding has more powerful data Binding capabilities. XML => ActivityMainBinding, activity_main_1. XML => ActivityMain1Binding.
val ac = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main) ac.user = p? .let { LoginModel(it,"200")}Copy the code
This very simple set of code does most of the work in this ecosystem and is superior to the MVP architecture in terms of development costs.