前言 :
各位同学大家好。最近在写了一点点安卓架构的demo mvp 代码架构模式,那么废话不多说我们正式开始
效果图
image.png分析
我们看到效果图, 我们很常见的一个人效果请求网络或者读取本地数据显示到列表控件上面 。相信同学们都很熟悉了,我就这边就不细讲了。时间有限
一般我们用原来的mvc 开发模式 要写一个model 处理数据请求 然后通过controller view 核model之间的关联,这样写是可有实现需求 但是我们在业务逻辑复杂了以后我们在controller 里面的代码会变成非常复杂 变很难维护。 这个时候我们就要考虑一个新架构 mvp 通过 Persenter 来讲 view 和model充分的解耦
具体实现
-
1普通版本mvp实现
-
activity 逻辑
package com.app.mvpdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import com.app.mvpdemo.adapter.MyAdapder;
import com.app.mvpdemo.persenter.QQMessagePersenter;
import com.app.mvpdemo.persenter.QQMessagePersenterv2;
import com.app.mvpdemo.view.QQMessageView;
import java.util.List;
public class MainActivity extends AppCompatActivity implements QQMessageView {
private ListView listView;
private QQMessagePersenter persenter;
private MyAdapder myAdapder;
private Button button;
private Context mContext=MainActivity.this;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView=findViewById(R.id.main_listview);
button=findViewById(R.id.main_btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(mContext,GridviewActivity.class));
}
});
persenter=new QQMessagePersenter(this);
persenter.getData();
}
@Override
public void showLoading() {
Toast.makeText(MainActivity.this,"加载数据中",Toast.LENGTH_SHORT).show();
}
@Override
public void showQQMessageInfo(List<QQmessage> data) {
myAdapder=new MyAdapder(MainActivity.this,data);
listView.setAdapter(myAdapder);
}
}
-
view 层
package com.app.mvpdemo.view;
import com.app.mvpdemo.QQmessage;
import java.util.List;
public interface QQMessageView {
void showLoading();
void showQQMessageInfo(List<QQmessage>data);
}
-
model 层
package com.app.mvpdemo.model;
import com.app.mvpdemo.QQmessage;
import java.util.List;
public interface QQMessageModel {
void loadQQMeaaage(QQMessageOnloadListener listener);
interface QQMessageOnloadListener{
void onComplete(List<QQmessage>data);
}
}
-
model层的实现层
package com.app.mvpdemo.model;
import com.app.mvpdemo.DataUtils;
public class QQMessageModelImpl implements QQMessageModel {
@Override
public void loadQQMeaaage(QQMessageOnloadListener listener) {
listener.onComplete(DataUtils.list());
}
}
-
模拟器数据
public static List<QQmessage>list(){
List<QQmessage>list=new ArrayList<>();
list.add(new QQmessage(R.drawable.icon1,"动脑学院课程真是好啊", "1"));
list.add(new QQmessage(R.drawable.icon2,"明天天气真不错啊哈哈哈","2"));
list.add(new QQmessage(R.drawable.icon3,"科技媒体王自如苹果册测评","3"));
list.add(new QQmessage(R.drawable.icon4,"那些痛的记忆落在存的泥土里","4"));
list.add(new QQmessage(R.drawable.icon5,"每天叫醒的我的不是闹钟而是代码","5"));
list.add(new QQmessage(R.drawable.icon6,"不要拦着我我要进阶一波","6"));
list.add(new QQmessage(R.drawable.icon7,"青山不改绿水长流","7"));
list.add(new QQmessage(R.drawable.icon8,"后悔有期有缘再见","8"));
return list;
}
-
Persenter
package com.app.mvpdemo.persenter;
import com.app.mvpdemo.QQmessage;
import com.app.mvpdemo.model.QQMessageModel;
import com.app.mvpdemo.model.QQMessageModelImpl;
import com.app.mvpdemo.model.QQMessageModelImplv2;
import com.app.mvpdemo.view.QQMessageView;
import java.util.List;
public class QQMessagePersenter {
QQMessageView qqMessageView;
QQMessageModel messageModel=new QQMessageModelImpl();
public QQMessagePersenter(QQMessageView qqMessageView) {
this.qqMessageView = qqMessageView;
}
public void getData(){
if(messageModel!=null){
if(messageModel!=null){
qqMessageView.showLoading();
}
messageModel.loadQQMeaaage(new QQMessageModel.QQMessageOnloadListener() {
@Override
public void onComplete(List<QQmessage> data) {
qqMessageView.showQQMessageInfo(data);
}
});
}
}
}
我们在Persenter 里面核心的逻辑是同时持有 view 层 model的引用是的我们可以讲 view model建立起联系 我们在设置在Persenter 的构造方法中传入 view 的实例 这样一来我们的activity的代码将会变得很简化
public class MainActivity extends AppCompatActivity implements QQMessageView {
private ListView listView;
private QQMessagePersenter persenter;
private MyAdapder myAdapder;
private Button button;
private Context mContext=MainActivity.this;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView=findViewById(R.id.main_listview);
button=findViewById(R.id.main_btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(mContext,GridviewActivity.class));
}
});
persenter=new QQMessagePersenter(this);
persenter.getData();
}
@Override
public void showLoading() {
Toast.makeText(MainActivity.this,"加载数据中",Toast.LENGTH_SHORT).show();
}
@Override
public void showQQMessageInfo(List<QQmessage> data) {
myAdapder=new MyAdapder(MainActivity.this,data);
listView.setAdapter(myAdapder);
}
}
在activity 里面我们只需要实例化 Persenter 并且传入view层的实现 然后调用 getData 获取数据即可 .
会产生的问题
普通的这mvp就讲完了看起来 代码比较简单 功能也是实现了 但是我们仔细观察就会发现 要是我们model在异步请求网络的时候数据还没有请求完成 用户就点击系统返回键关闭了当前activity 的时候就发生内存泄漏 这是要我们在持有view引用的时候就要用弱引用
处理内存泄漏 persneter 修改 版
package com.app.mvpdemo.persenter;
import com.app.mvpdemo.QQmessage;
import com.app.mvpdemo.model.QQMessageModel;
import com.app.mvpdemo.model.QQMessageModelImplv2;
import com.app.mvpdemo.view.QQMessageView;
import java.lang.ref.WeakReference;
import java.util.List;
public class QQMessagePersenterv2 <T extends QQMessageView>{
// view 引用
// QQMessageView qqMessageView;
// 弱引用
protected WeakReference<T> mViewRef;
QQMessageModel messageModel=new QQMessageModelImplv2();
public QQMessagePersenterv2() {
super();
}
public void getData(){
if(messageModel!=null){
if(mViewRef.get()!=null){
mViewRef.get().showLoading();
}
messageModel.loadQQMeaaage(new QQMessageModel.QQMessageOnloadListener() {
@Override
public void onComplete(List<QQmessage> data) {
QQMessageView qqMessageView=mViewRef.get();
if(qqMessageView!=null){
mViewRef.get().showQQMessageInfo(data);
}
}
});
}
}
public void attachView(T view){
mViewRef=new WeakReference<T>(view);
}
public void detachView(){
if(mViewRef!=null){
mViewRef.clear();
}
}
}
我们这里 将view 层引用改成弱引用
protected WeakReference<T> mViewRef;
然后提供了 attachView detachView 创建view实例和销毁的方法
public void attachView(T view){
mViewRef=new WeakReference<T>(view);
}
public void detachView(){
if(mViewRef!=null){
mViewRef.clear();
}
}
在activtiy 中调用处理
package com.app.mvpdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.GridView;
import android.widget.Toast;
import com.app.mvpdemo.adapter.MyAdapder;
import com.app.mvpdemo.persenter.QQMessagePersenterv2;
import com.app.mvpdemo.view.QQMessageView;
import java.util.List;
public class GridviewActivity extends AppCompatActivity implements QQMessageView {
private GridView gridView;
private QQMessagePersenterv2 persenterv2;
private Context mContext=GridviewActivity.this;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gridview);
gridView=findViewById(R.id.gridview);
findViewById(R.id.grid_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(mContext,TestActivity.class));
}
});
persenterv2=new QQMessagePersenterv2();
persenterv2.attachView(this);
persenterv2.getData();
}
@Override
public void showLoading() {
Toast.makeText(mContext,"加载数据中..... ",Toast.LENGTH_SHORT).show();
}
@Override
public void showQQMessageInfo(List<QQmessage> data) {
gridView.setAdapter(new MyAdapder(mContext,data));
}
@Override
protected void onDestroy() {
super.onDestroy();
if(persenterv2!=null){
persenterv2.detachView();
}
}
}
这样写虽然能解决问题 但是我们随之又发现 我们activity 里面代码无形增加了不少 这样mvp架构设计不够完美
最终版本
-
BasePersenter
我们写了一个 BasePersenter 里面来处理 detachView 和attachView
package com.app.mvpdemo.persenter;
import java.lang.ref.WeakReference;
public class BasePersenter<T> {
// view 引用
// 弱引用
protected WeakReference<T> mViewRef;
public void attachView(T view){
mViewRef=new WeakReference<T>(view);
}
public void detachView(){
if(mViewRef!=null){
mViewRef.clear();
}
}
protected T getView(){
return mViewRef.get();
}
}
我们自己的 QQMessagePersenterv3 只需要继承 BasePersenter 并且传入的view的对象 即可
package com.app.mvpdemo.persenter;
import com.app.mvpdemo.QQmessage;
import com.app.mvpdemo.model.QQMessageModel;
import com.app.mvpdemo.model.QQMessageModelImplv2;
import com.app.mvpdemo.view.QQMessageView;
import java.util.List;
public class QQMessagePersenterv3 extends BasePersenter<QQMessageView>{
QQMessageModel messageModel=new QQMessageModelImplv2();
public QQMessagePersenterv3() {
super();
}
public void getData(){
if(messageModel!=null){
if(getView()!=null){
getView().showLoading();
}
messageModel.loadQQMeaaage(new QQMessageModel.QQMessageOnloadListener() {
@Override
public void onComplete(List<QQmessage> data) {
QQMessageView qqMessageView=getView();
if(qqMessageView!=null){
qqMessageView.showQQMessageInfo(data);
}
}
});
}
}
}
定义baseactivtiy
package com.app.mvpdemo;
import android.app.Activity;
import android.os.Bundle;
import androidx.annotation.Nullable;
import com.app.mvpdemo.persenter.BasePersenter;
public abstract class BaseActivity <V,T extends BasePersenter<V>> extends Activity {
public T qqMessagePersenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
qqMessagePersenter=createPerenter();
qqMessagePersenter.attachView((V)this);
}
protected abstract T createPerenter();
@Override
protected void onDestroy() {
super.onDestroy();
qqMessagePersenter.detachView();
}
}
在baseactivity 里面我们定义一个 createPerenter 的抽象方法 这样我们让我们集成baseactivity 的activity 来实现这个抽象方法 当需要实现哪个 perenter实例 就去实现即可
package com.app.mvpdemo;
import android.content.Context;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.Toast;
import com.app.mvpdemo.adapter.MyAdapder;
import com.app.mvpdemo.persenter.QQMessagePersenterv3;
import com.app.mvpdemo.view.QQMessageView;
import java.util.List;
public class TestActivity extends BaseActivity <QQMessageView, QQMessagePersenterv3> implements QQMessageView {
private Context mContext=TestActivity.this;
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
listView=findViewById(R.id.test_listview);
qqMessagePersenter.getData();
}
@Override
protected QQMessagePersenterv3 createPerenter() {
return new QQMessagePersenterv3();
}
@Override
public void showLoading() {
Toast.makeText(mContext,"加载数据中..... ",Toast.LENGTH_SHORT).show();
}
@Override
public void showQQMessageInfo(List<QQmessage> data) {
listView.setAdapter(new MyAdapder(mContext,data));
}
}
到此我们最终封装的版本机OK 我们在不断抽象封装之后整个 mvp架构就趋近成熟 ,整个架构设计都是需要我们自己一步一步提炼 到一个高度解构并且代码结构清晰的程度。
最后总结
mvc mvp mvvm 这三种代码架构设计出来很久了但是很多都只是停留在配合框架上面去使用 ,其实这个是自己的设计跟什么网络请求库无关 这个也是需要同学们自己去不断抽象 提炼 我们今天只是记录下其实没有什么想多说的。最后希望我的文章能帮助到各位解决问题 ,以后我还会贡献更多有用的代码分享给大家。各位同学如果觉得文章还不错 ,麻烦给关注和star,小弟在这里谢过啦!
网友评论