Android学习探索之运用MVP设计模式实现项目解耦

前言:

    一直致力于提高开发效率降低项目耦合,今天想抽空学习一下MVP架构设计模式,学习一下如何运用到项目中。

MVP架构设计模式

   MVP模式是一种架构设计模式,也是一种经典的界面模式。MVP中的M代表Model, V是View, P是Presenter。

  • Model 业务逻辑和实体模型 
  • View 代表对应布局文件以及一个将UI界面提炼而抽象出来的接口。 
  • Presenter Model和View之间的桥梁

为什么采用MVP

  • 降低耦合度
  • 模块职责划分明显
  • 利于测试驱动开发
  • 代码复用
  • 隐藏数据
  • 代码灵活性

 举个栗子说明一下

  先看下整个栗子的结构示意图

1)首先我们先看M层

Model代表业务逻辑和实体模型,栗子中的M层包含一个实体类UserEntity,具体代码如下:

public class UserEntity {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

一个获取user列表的契约接口类IUserModel

public interface IUserModel {

    void loadUserEntities(IGetUserEntitiesListener listener);
}

一个实现IUserModel的实现类UserModelImpl

public class UserModelImpl implements IUserModel {
    @Override
    public void loadUserEntities(final IGetUserEntitiesListener listener) {
        //模拟网络请求数据过程
        new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
            @Override
            public void run() {
                List<UserEntity> userModels = new ArrayList<>();
                int testCount = 20;
                for (int i = 0; i < testCount; i++) {
                    UserEntity userModel = new UserEntity();
                    userModel.setAge(i * 5);
                    userModel.setName(String.format("李%d", i));
                    userModels.add(userModel);
                }
                listener.onGetUserEntities(userModels);
            }
        }, 3000);
    }
}

回调结果的IGetUserEntitiesListener 接口类

public interface IGetUserEntitiesListener {

    void onGetUserEntities(List<UserEntity> userEntities);

}

2)V层就是页面的展示与加载

这里的V层为一个接口契约类和Activity,负责View的绘制以及与用户交互,首先看下契约接口类

public interface ILoadDataView<T> {

    void startLoading();//开始加载

    void loadFailed();//加载失败

    void loadSuccess(List<T> list);//加载成功

    void finishLoading();//结束加载

}

 Activity代码如下

public class MainActivity extends AppCompatActivity implements ILoadDataView<UserEntity> {
    private MyAdapter mMyAdapter;
    private ProgressDialog mProgressDialog;
    private LoadUserEntitiesPresenter mLoadListPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
    }

    private void initViews() {
        ListView testListView = (ListView) findViewById(R.id.test_listView);
        mMyAdapter = new MyAdapter(this);
        testListView.setAdapter(mMyAdapter);
        mLoadListPresenter = new LoadUserEntitiesPresenter(this);
        findViewById(R.id.test_button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mMyAdapter.removeDatas();
                mMyAdapter.notifyDataSetChanged();
                mLoadListPresenter.loadUserEntities();
            }
        });
    }

    @Override
    public void startLoading() {
        mProgressDialog = new ProgressDialog(this);
        mProgressDialog.setMessage("正在加载中");
        mProgressDialog.show();
    }

    @Override
    public void loadFailed() {

    }

    @Override
    public void loadSuccess(List<UserEntity> list) {
        mMyAdapter.addDatas(list);
        mMyAdapter.notifyDataSetChanged();
    }

    @Override
    public void finishLoading() {
        if (mProgressDialog != null) {
            mProgressDialog.dismiss();
            mProgressDialog = null;
        }
    }

3)P层负责完成View于Model间的交互,由P分别操作M层和V层,是他们之间的桥梁

 首先看下Presenter的实现,包括一个ILoadUserEntitiesPresenter契约接口类和LoadUserEntitiesPresenter实现类

ILoadUserEntitiesPresenter类代码

public interface ILoadUserEntitiesPresenter {

    void loadUserEntities();

}
LoadUserEntitiesPresenter实现类
public class LoadUserEntitiesPresenter implements ILoadUserEntitiesPresenter {
    private ILoadDataView<UserEntity> mILoadListView;
    private IUserModel mUserModel;

    public LoadUserEntitiesPresenter(ILoadDataView<UserEntity> mILoadListView) {
        this.mILoadListView = mILoadListView;
        this.mUserModel = new UserModelImpl();
    }

    @Override
    public void loadUserEntities() {
        mILoadListView.startLoading();
        mUserModel.loadUserEntities(new IGetUserEntitiesListener() {
            @Override
            public void onGetUserEntities(List<UserEntity> userEntities) {
                if (userEntities != null && !userEntities.isEmpty()) {
                    mILoadListView.loadSuccess(userEntities);
                } else {
                    mILoadListView.loadFailed();
                }
                mILoadListView.finishLoading();
            }
        });
    }
}

为了保证栗子能够正常运行,顺便贴出其他的代码

public class MyAdapter extends BaseAdapter {
    private List<UserEntity> mUserModels;
    private Context mContext;

    public MyAdapter(Context mContext) {
        this.mContext = mContext;
        this.mUserModels = new ArrayList<>();
    }

    @Override
    public int getCount() {
        return mUserModels != null ? mUserModels.size() : 0;
    }

    @Override
    public Object getItem(int position) {
        return mUserModels.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if (convertView == null) {
            viewHolder = new ViewHolder();
            convertView = viewHolder.bindVIew();
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        viewHolder.bindData(position);
        return convertView;
    }

    public void addDatas(List<UserEntity> modelList) {
        if (modelList == null || modelList.isEmpty()) {
            return;
        }
        mUserModels.addAll(modelList);
    }

    public void removeDatas() {
        mUserModels.clear();
    }

    public class ViewHolder {

        private TextView mTextView;

        public View bindVIew() {
            View convertView = LayoutInflater.from(mContext).inflate(R.layout.item_listview, null);
            mTextView = (TextView) convertView.findViewById(R.id.test_textview);
            return convertView;
        }

        public void bindData(int position) {
            UserEntity userModel = mUserModels.get(position);
            mTextView.setText(String.format("name:%s \nage:%d", userModel.getName(), userModel.getAge()));
        }
    }

}
MyAdapter
<?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="com.whoislcj.testmvp.MainActivity">

    <Button
        android:id="@+id/test_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:text="测试mvp"/>

    <ListView
        android:id="@+id/test_listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

</LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/test_textview"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:minHeight="50dp"
          android:layout_margin="10dp"
          android:background="@android:color/white"
          android:gravity="center"
          android:orientation="vertical"
          android:textColor="@android:color/black"
          android:textSize="16sp"/>
item_listview.xml

总结:

 这里仅仅就是MVP的简单实现,为了方便简单的认识MVP分层以及各层的职责与作用。

 

posted on 2017-04-20 08:50  总李写代码  阅读(4849)  评论(5编辑  收藏  举报