Mvp小例子
前几天在网上看了一些Mvp的文章,很大一部分的解决了Activity中代码臃肿的问题。今天自己写了一个小例子,有所收获,大家也可以学习参考一下。
M–model 数据实体类
V–View 这里主要是和用户交互的Activity
P–presenter 具体的来处理代码逻辑(其中会持有一个Activity的引用)
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
>
<cn.cook.mvpdemo.view.NoteEditText
android:gravity="top"
android:id="@+id/edt_content"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp" />
<LinearLayout
android:gravity="center"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="50dp">
<Button
android:id="@+id/btn_pre"
android:text="上一步"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content" /> <Button
android:text="保存"
android:id="@+id/btn_save"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content" /> <Button
android:text="下一步"
android:id="@+id/btn_next"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
其中NoteEditText是一个简单的继承EditText的控件。
代码如下:
public NoteEditText(Context context) {
super(context);
}
public NoteEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoteEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 点击保存时候创建一个Memoto对象
* @return
*/
public Memoto onSave(){
return new Memoto(getText().toString(),getSelectionStart());
}
/**
* 根据传进来的Memoto修改显示
* @param memoto
*/
public void restore(Memoto memoto){
setText(memoto.content);
setSelection(memoto.cursor);
}
Momoto 是一个简单的数据实体
public Memoto(String content, int cursor) {
this.content = content;
this.cursor = cursor;
}
/**
* 文本
*/
public String content;
/**
* 光标所在位置
*/
public int cursor;
MainActivity中的代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener,IEdtView {
private NoteEditText mEdtContent;//输入框
private Button mBtnPre;//上一步
private Button mBtnNext;//下一步
private Button mBtnSave;//保存
private ImplEdtPresenter mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
/**
* 初始化
*/
private void initView() {
mEdtContent = (NoteEditText) findViewById(R.id.edt_content);
mBtnPre = (Button) findViewById(R.id.btn_pre);
mBtnNext = (Button) findViewById(R.id.btn_next);
mBtnSave = (Button) findViewById(R.id.btn_save);
mBtnPre.setOnClickListener(this);
mBtnNext.setOnClickListener(this);
mBtnSave.setOnClickListener(this);
//创建Presenter,通过构造precenter会持有一个activity的对象引用
mPresenter=new ImplEdtPresenter(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_pre:
mPresenter.onPre();
break;
case R.id.btn_next:
mPresenter.onNext();
break;
case R.id.btn_save:
mPresenter.onSave(mEdtContent.onSave());
break;
}
}
@Override
public void preEdt(Memoto memoto) {
mEdtContent.restore(memoto);
}
@Override
public void nextEdt(Memoto memoto) {
mEdtContent.restore(memoto);
}
@Override
public void save() {
Toast.makeText(MainActivity.this, "保存成功", Toast.LENGTH_SHORT).show();
}
}
IEditView 是一个接口,用来处理Activity的显示
public interface IEdtView {
void preEdt(Memoto memoto);
void nextEdt(Memoto memoto);
void save();
}
Activity实现了该接口,precenter持有Activity的引用,因此我们可以再precenter中处理完数据之后,直接的来通过precenter更新UI。
public interface IEdtPresenter {
void onSave(Memoto memoto);
void onPre();
void onNext();
}
三个方法对应Activity中的三个操作,具体的逻辑要在这三个方法中完成。
public class ImplEdtPresenter implements IEdtPresenter {
private IEdtView iEdtView;
private NoteCaretaker noteCaretaker;
public ImplEdtPresenter(IEdtView iEdtView) {
this.iEdtView = iEdtView;
noteCaretaker = new NoteCaretaker();
}
@Override
public void onSave(Memoto memoto) {
noteCaretaker.save(memoto);
iEdtView.save();
}
@Override
public void onPre() {
iEdtView.preEdt(noteCaretaker.onPre());
}
@Override
public void onNext() {
iEdtView.nextEdt(noteCaretaker.onNext());
}
}
实现IEdtPresenter接口,在其中做Activity中三种操作的逻辑。具体的操作我们放到了NoteCaretaker中,他来具体的实现保存,上一步,下一步的操作。
private ArrayList<Memoto> memotos = new ArrayList<>();
private int mIndex;
public void save(Memoto memoto) {
if (memoto == null) {
throw new NullPointerException();
}
if (!memotos.contains(memoto)) {
memotos.add(memoto);
mIndex = memotos.size() - 1;
}
}
public Memoto onPre() {
mIndex = mIndex > 0 ? --mIndex : mIndex;
return memotos.get(mIndex);
}
public Memoto onNext() {
mIndex = mIndex < memotos.size() - 1 ? ++mIndex : mIndex;
return memotos.get(mIndex);
}
实现没有什么难度,就是用List来保存,上一步,下一步都是来操作List中的数据。
我的总结:
我认为的MVP就是,Activity只管显示,定义一个接口来管理所有需要更新UI的方法,ACtivity实现这个接口。定义Precenter接口来管理所有需要处理逻辑的方法,针对Activity中的不同操作,来实现不同的逻辑。通过持有实现了管理UI接口的Activity,在获取到数据是,做不同的更新UI工作。例如本例中我们定义了一个接口Precenter来处理针对不同Activity的操作的不同操作。同时我们定义了一个在处理完数据之后管理所有UI更新的接口,在Precenter中我们获取到数据之后,通过Activity回调这些方法。这就是我理解的MVP。希望对大家有帮助。有什么错误的话希望大家见谅。
另外,因为Precenter持有Activity的引用,所以大家可以再Activity销毁的时候,把Precenter对象置为空,防止内存泄漏。