MVP 理论知识
在MVP 架构中跟MVC类似的是同样也分为三层。
Activity 和Fragment 视为View层,负责处理 UI。
Presenter 为业务处理层,既能调用UI逻辑,又能请求数据,该层为纯Java类,不涉及任何Android API。
Model 层中包含着具体的数据请求,数据源。
其实道理个个都懂,关键就是代码。
以一个demo 解释:
这个demo 已经充分体现出了mvp模式。
1 Activity 持有Presenter 的引用,当activity 请求数据,做其他操作,或者 设置数据(TextView 设置数据时候,就通过Presenter 进行处理。所以就直接通过Presenter 方法调用。
2Presenter 持有了IUserModel 接口,IUserModel接口的引用,业务逻辑都在这里实现。当业务请求数据时候,就通过Model层进行请求处理。
就如上图mUserModel.load(id); 方法,然后就通过Activity 实现Model进行交互了。
public class UserActivity extends Activity implements OnClickListener,
IUserView {
private EditText mFirstNameEditText, mLastNameEditText, mIdEditText;
private Button mSaveButton, mLoadButton;
private UserPresenter mUserPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findWidgets();
mUserPresenter = new UserPresenter(this);
mSaveButton.setOnClickListener(this);
mLoadButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.saveButton:
mUserPresenter.saveUser(getID(), getFristName(),
getLastName());
break;
case R.id.loadButton:
mUserPresenter.loadUser(getID());
break;
default:
break;
}
}
@Override
public void setFirstName(String firstName) {
// TODO Auto-generated method stub
mFirstNameEditText.setText(firstName);
}
@Override
public void setLastName(String lastName) {
// TODO Auto-generated method stub
mLastNameEditText.setText(lastName);
}
@Override
public int getID() {
// TODO Auto-generated method stub
return Integer.parseInt(mIdEditText.getText().toString());
}
@Override
public String getFristName() {
// TODO Auto-generated method stub
return mFirstNameEditText.getText().toString();
}
@Override
public String getLastName() {
// TODO Auto-generated method stub
return mLastNameEditText.getText().toString();
}
void findWidgets() {
mFirstNameEditText = (EditText) findViewById(R.id.first_name_edt);
mLastNameEditText = (EditText) findViewById(R.id.last_name_edt);
mIdEditText = (EditText) findViewById(R.id.id_edt);
mSaveButton = (Button) findViewById(R.id.saveButton);
mLoadButton = (Button) findViewById(R.id.loadButton);
}
}
这个是最基础的mvp。
public class UserModel implements IUserModel {
private String mFristName;
private String mLastName;
private int mID;
private SparseArray<UserBean> mUsererArray = new SparseArray<UserBean>();
@Override
public void setID(int id) {
// TODO Auto-generated method stub
mID = id;
}
@Override
public void setFirstName(String firstName) {
// TODO Auto-generated method stub
mFristName = firstName;
}
@Override
public void setLastName(String lastName) {
// TODO Auto-generated method stub
mLastName = lastName;
UserBean UserBean = new UserBean(mFristName, mLastName);
mUsererArray.append(mID, UserBean);
}
@Override
public UserBean load(int id) {
// TODO Auto-generated method stub
mID = id;
UserBean userBean = mUsererArray.get(mID, new UserBean("not found",
"not found"));
return userBean;
}
}
由于实际项目开发中,遇到的业务可能比较多,那么就要通过抽象类进行封装。
Presenter :其中开发中肯定会有很多个,所以需要抽取封装,也是通过<P> 进行封装。
Activity :既然Presenter 类是有多个,那么就要抽取BaseMvpActivity 里面进行封装了。
从基本上看,presenter 需要绑定要view 和model ,也就是说view层跟model层必须要引用的。
所以可以抽取封装出来。
========================================封装好的代码·===================================
直接上代码。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/but"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="获得数据" />
<TextView
android:id="@+id/msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>
普通布局文件。
package com.twc.mvpi;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.twc.mvpi.base.BaseMvpActivity;
import com.twc.mvpi.presenter.IMainPresenter;
import com.twc.mvpi.view.IMainView;
public class MainActivity extends BaseMvpActivity<IMainView, IMainPresenter> implements IMainView {
private TextView msgt;
private Button but;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
but = findViewById(R.id.but);
msgt = findViewById(R.id.msg);
but.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getmPresenter().getIMainMsg("我是请求接口的参数");
}
});
}
@Override
protected IMainPresenter createPresenter() {
return new IMainPresenter();
}
@Override
public void otherMethod() {
Toast.makeText(this, "我调用了另外的方法", Toast.LENGTH_LONG).show();
}
@Override
public void refreshView(String msg) {
msgt.setText(msg);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
这个是MainActivity 的文件。
流程,用户点击了按钮,需要请求接口。
getmPresenter(): 方法是什么,其实也是一个创建Presenter 的方法,它是封装到BaseMvpActivity 中,
可以直接获取,这样其他activity 只要继承BasePresenter 这个类就可以直接获取了。
package com.twc.mvpi.base;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
public abstract class BaseMvpActivity<V extends MvpView, T extends BasePresenter<V>> extends AppCompatActivity {
private T mPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (mPresenter == null) {
mPresenter = createPresenter();
}
if (mPresenter != null && !mPresenter.isViewAttached()) {
mPresenter.attachView((V) this);
mPresenter.baseInit(this);
}
}
public T getmPresenter() {
return mPresenter;
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mPresenter != null) {
mPresenter.detchView();
}
}
protected abstract T createPresenter();
}
可以见到有个抽象方法,是在子类实现的东西,就是创建子Presenter。
这个demo 用IMainPresenter 继承封装BasePresenter.
package com.twc.mvpi.presenter;
import android.content.Context;
import com.twc.mvpi.base.BasePresenter;
import com.twc.mvpi.model.IModelImp;
import com.twc.mvpi.view.IMainView;
public class IMainPresenter extends BasePresenter<IMainView> implements OnDataListener {
private IModelImp iModelImp;
@Override
public void init(Context context) {
iModelImp = new IModelImp(this);
}
public void getIMainMsg(String but_is_but) {
iModelImp.getDataFormNet(but_is_but);
}
@Override
public void getData(String msg) {
getmMvpView().otherMethod();
getmMvpView().refreshView(msg);
}
}
之前也是说了BasePresenter 需要绑定 view,跟model 的引用。
所以,在子的presenter 里面需要初始化 model 的引用。也就是Imodel
package com.twc.mvpi.model;
import com.twc.mvpi.presenter.OnDataListener;
public class IModelImp implements IModelInterface {
OnDataListener iMainPresenter;
public IModelImp(OnDataListener iMainPresenter) {
this.iMainPresenter = iMainPresenter;
}
@Override
public void getDataFormNet(String msg) {
iMainPresenter.getData(msg + ",我通过参数从网络获取的数据");
}
}
这里Model 实现了一个回调接口,进行数据回调。
来到这里,在旅一次流程。
1activity --->按钮点击---> 获取 getPresenter()方法 获取对应的mPresenter 的对象,
2获取对象之后 就getIMainMsg()方法,
3然后就用 iModelImp调用getDataFormNet方法。
这里获取数据之后就回调接口,将数据传递给presenter 。
presenter 里面 就通过
getmMvpView().otherMethod();
getmMvpView().refreshView(msg);
通过开头实现的方法getmMvpView()获取
mMvpView 的引用实例IMainView。
就刷新数据,
最后activity里面就获得了数据。进行数据刷新。
。
总结:
activity 里面有业务,就通过 方法 写在子presenter 里面,presenter 里面有model 的实现类,model就请求数据
请求回来后通过接口回调到子presenter 里面,子presenter 里面就通过getView 方法调用,view接口方法刷新调用activity。