之前的项目一直使用mvc的模式编写,动不动一个Activity的代码就达到了成百上千行,每次改需求和BUG都需要上下滑从几百行代码里找到关键位置十分的难受+浪费时间.于是学习了一下MVP模式,解耦一下代码,方便后期的维护.
一.回顾MVC
在MVC里,View是可以直接访问Model的!从而,View里会包含Model信息,不可避免的还要包括一些业务逻辑。1.M(Model)模型层
对数据库的操作,访问网络等都应该放在Model中
2.V(View)视图层
即xml文件对界面的描述
3.C(control)控制层
Android的控制层通常交给了Actvity,所以尽量不要再Acticity中写代码,应该将一些业务逻辑交给Model层处理
二.学习MVP
在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部.而在MVC中View会直接从Model中读取数据而不是通过 Controller
1.M(Model)模型层
2.V(View)视图层
即xml文件对界面的描述
3.P(Presenter)
负责在Model和View之间,从model里取出数据,格式化后在View上展示(解决如何把数据和用户界面放在一起)。
而和MVC最大的区别在于Model和View完全被Presenter隔开了,Presenter作为它们之间的中间人去传递所有数据。
三:从新建项目开始学习MVC
3.1 新建项目并分包
3.2 创建BaseActivity并被MainActivity继承
BaseActivity放在根目录,MainActivity放在view -> ui 包中
public abstract class BaseActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initUI();
initData();
initLinsenter();
}
public abstract void initUI();
public abstract void initData();
public abstract void initLinsenter();
}
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
//继承至baseActivity的方法
@Override
public void initUI() {
setContentView(R.layout.activity_main);
}
//继承至baseActivity的方法
@Override
public void initData() {
}
//继承至baseActivity的方法
@Override
public void initLinsenter() {
}
}
3.3 创建请求json解析数据数据的bean类
bean类放在model -> bean 包中
public class BookBean {
public String name;
public int price;
public BookBean(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
3.4 创建IBookView
放在view包下
这里主要是包含了Activity的一系列关于UI操作,然后用我们的Activity去实现,这样Presenter就可以调用了。
public interface IBookView {
/**
* 刷新数据
*/
void refreshAdapter();
/**
* 提示吐司
* @param msg
*/
void Toast(String msg);
/**
* 请求数据为空
*/
void OnEmpty();
}
3.5 创建创建全局通用的请求数据回调ValueCallBack
public interface ValueCallBack<T> {
//请求成功回调
void Onsuccess(T t);
//请求失败的回调
void OnError(String msg);
}
3.6 创建IBuyBookModel
public interface IBuyBookModel {
/**
* 请求网络取数据
* @param callback
*/
void getTestData(ValueCallback<List<BookBean>> callback);
/**
* 返回本地adapter的数据
* @return
*/
List<BookBean> getAdapterData();
}
3.7 创建BuyBookModel实现IBuyBookModel,进行网络请求
放在model -> task 包中
public class BuyBookModel implements IBuyBookModel {
private final ArrayList<BookBean> bookBeans;
public BuyBookModel() {
bookBeans = new ArrayList<>();
}
//重写至IBuyBookModel
@Override
public void getTestData(final ValueCallBack<List<BookBean>> callback) {
//模拟网络请求
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
ArrayList<BookBean> bookBeans = new ArrayList<>();
bookBeans.add(new BookBean("android",99));
bookBeans.add(new BookBean("ios",188));
bookBeans.add(new BookBean("java",666));
bookBeans.add(new BookBean("php",123));
//随机数模拟返回的code
Random random = new Random();
int code = random.nextInt(5);
if(code==3){
callback.Onsuccess(bookBeans);
}else{
callback.OnError("暂无数据");
}
}
}, 1000);
}
//重写至IBuyBookModel
@Override
public List<BookBean> getAdapterData() {
return bookBeans;
}
}
3.8 创建BasePresenter
放在根目录下
/**
* 这个是所有Presenter的基类,里面有个initData()方法,基本每个Presenter都要处理网络请求,所以有了这么一个基类
为什么用了个泛型?为了让人一看这个Presenter就知道这对应着哪个Activity,实际上这可以不加的,但是我觉得加上去更好。便于后来人也便于自己以后再来修改这个类。
* @param <T>
*/
public abstract class BasePresenter<T extends BaseActivity> {
abstract void initData();
}
3.9 创建IBuyBookPresenter以供BuyBookPresenter实现
放在presenter包下
public interface IBuyBookPresenter {
List<BookBean> getAdapterData();
}
/**
* 在此处联系model和view
*/
public class BuyBookPresenter extends BasePresenter<MainActivity> implements IBuyBookPresenter {
public IBuyBookModel bookModel;
public IBookView iBookView;
public BuyBookPresenter(IBookView iBookView) {
this.iBookView = iBookView;
this.bookModel = new BuyBookModel();
}
//重写IBuyBookPresenter的方法
@Override
public List<BookBean> getAdapterData() {
return bookModel.getAdapterData();
}
//重写BasePresenter的方法
@Override
public void initData() {
//弹出dialog
bookModel.getTestData(new ValueCallBack<List<BookBean>>() {
@Override
public void Onsuccess(List<BookBean> bookBeans) {
//关闭dialog
bookModel.getAdapterData().addAll(bookBeans);
iBookView.refreshAdapter();
}
@Override
public void OnError(String msg) {
//关闭dialog
iBookView.OnEmpty();
iBookView.Toast(msg);
}
});
}
}
4.1 BaseActivity加入presenter
public abstract class BaseActivity <T extends BasePresenter> extends Activity {
protected T basepresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
basepresenter = initPresent();
initUI();
initData();
initLinsenter();
}
public abstract T initPresent();
public abstract void initUI();
public abstract void initData();
public abstract void initLinsenter();
}
4.2 最终Activity extends BaseActivity<BuyBookPresenter> implements IBuyBookView
放在 view -> ui 包下
public class MainActivity extends BaseActivity<BuyBookPresenter>implements IBookView {
private RecyclerView recyclerView;
private BaseAdapter baseAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public BuyBookPresenter initPresent() {
return new BuyBookPresenter(this);
}
//继承至baseActivity的方法
@Override
public void initUI() {
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.rv);
}
//继承至baseActivity的方法
@Override
public void initData() {
baseAdapter = new BaseAdapter(basepresenter.getAdapterData(), this);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyclerView.setAdapter(baseAdapter);
basepresenter.initData();
}
//继承至baseActivity的方法
@Override
public void initLinsenter() {
}
//实现至IBookView的方法
@Override
public void refreshAdapter() {
baseAdapter.notifyDataSetChanged();
}
//实现至IBookView的方法
@Override
public void Toast(String msg) {
Toast.makeText(getApplicationContext(),msg,Toast.LENGTH_SHORT).show();
}
//实现至IBookView的方法
@Override
public void OnEmpty() {
//展示暂无数据的逻辑,如显示为空的图片,隐藏列表
}
}
附件:
BaseAdapter.java:
放在view -> adapter 包下
package com.demo.zengke.mvpdemo.view.adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.demo.zengke.mvpdemo.R;
import com.demo.zengke.mvpdemo.model.bean.BookBean;
import java.util.List;
/**
* Created by Administrator on 2018/5/24 0024.
*/
public class BaseAdapter extends RecyclerView.Adapter<BaseAdapter.BaseHolder> {
public List<BookBean> mList;
public Context mcontext;
public BaseAdapter(List<BookBean> lists, Context context) {
this.mList = lists;
this.mcontext = context;
}
@Override
public BaseHolder onCreateViewHolder(ViewGroup parent, int viewType) {
BaseHolder holder = new BaseHolder(LayoutInflater.from(mcontext).inflate(R.layout.item_anjianrenyuan_dailiren, parent,
false));
return holder;
}
@Override
public void onBindViewHolder(BaseHolder holder, int position) {
holder.textView.setText(mList.get(position).getName()+mList.get(position).getPrice());
}
@Override
public int getItemCount() {
return mList.size();
}
public class BaseHolder extends RecyclerView.ViewHolder {
TextView textView;
public BaseHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.tv);
}
}
}
R.layout.item_anjianrenyuan_dailiren.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:text="========="
android:textSize="15dp" />
</RelativeLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
tools:context="com.demo.zengke.mvpdemo.view.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>
最后:
附上,目录结构图:
运行效果图:
感谢大佬点击打开链接
以后有空再上传demo