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())); } } }

<?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>

<?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"/>
总结:
这里仅仅就是MVP的简单实现,为了方便简单的认识MVP分层以及各层的职责与作用。
干我们这行,啥时候懈怠,就意味着长进的停止,长进的停止就意味着被淘汰,只能往前冲,直到凤凰涅槃的一天!
分类:
Android学习探索
标签:
Android MVP
, MVP解耦
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?