热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AndroidMvp架构设计与性能优化

AndroidMvp架构设计与性能优化什么是mvp架构设计?MVP是模型(Model)、视图(View)、主持人(Presenter)的缩写,分别代表项目中3个不同的模块。模型

Android Mvp架构设计与性能优化


什么是mvp架构设计?

MVP是模型(Model)、视图(View)、主持人(Presenter)的缩写,分别代表项目中3个不同的模块。

  模型(Model):负责处理数据的加载或者存储,比如从网络或本地数据库获取数据等;

  视图(View):负责界面数据的展示,与用户进行交互;

  主持人(Presenter):相当于协调者,是模型与视图之间的桥梁,将模型与视图分离开来。

  如下图所示,View与Model并不直接交互,而是使用Presenter作为View与Model之间的桥梁。其中Presenter中同时持有Viwe层以及Model层的Interface的引用,而View层持有Presenter层Interface的引用。当View层某个界面需要展示某些数据的时候,首先会调用Presenter层的某个接口,然后Presenter层会调用Model层请求数据,当Model层数据加载成功之后会调用Presenter层的回调方法通知Presenter层数据加载完毕,最后Presenter层再调用View层的接口将加载后的数据展示给用户。这就是MVP模式的整个核心过程。


为什么要mvp架构设计?

书面的说法就是为了解耦,为了可维护性,可扩展性。简而言之就是OCP开闭原则,对于扩展开放,对于修改关闭。

但是我更想用个人实战经验来说明架构设计在开发中的好处。初学android的时候觉得android很麻烦,要写很多的配置文件,加上自己也没有多么高深的架构设计能力,所以曾经写一个应用一个service达到了近1000行代码。对,你没听错,后期维护的时候很恶心人,我现在看到那个项目就想吐。这就是没有架构胡乱敲代码所导致的后果。还好google工程师在android里其实内置了很多的设计模式,所以我们的代码才没有更恶心下去。用了mvp架构设计后个人觉得非常的方便,代码风格发生了很大的变化,开始习惯使用泛型,开始习惯不写重复代码,并且开始自己封装一些简单的框架,抽出一些公共的方法。由于上面也讲了mvp具体是怎么回事,我就不多啰嗦了。

AndroidMVP架构实战:

包结构:

renyou.com.mvp.activity

renyou.com.mvp.model

renyou.com.mvp.view

renyou.com.mvp.presenter

renyou.com.mvp.bean

renyou.com.mvp.data

renyou.com.mvp.adapter

renyou.com.mvp.activity

public class MvpActivity extends AppCompatActivity implements MvpView{
private ListView listview;
private MvpAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp);
initView();

new MvpPresenterV1(this).fetch();
}


private void initView() {
listview= (ListView) findViewById(R.id.lv_main);
}

@Override
public void showLoading() {
Toast.makeText(getApplicationContext(),"正在加载",Toast.LENGTH_LONG).show();
}

@Override
public void showDatas(List datas) {
mAdapter=new MvpAdapter(getApplicationContext(), datas);
listview.setAdapter(mAdapter);
}
}

renyou.com.mvp.model

 
 
MvpModel:model层接口
public interface MvpModel {    void loadDatas(DataOnLoadingListener listener);    interface DataOnLoadingListener{        void onComplete(Listdatas);    }}
MvpModelImplV1:model层实现类
public class MvpModelImplV1 implements MvpModel {    @Override    public void loadDatas(DataOnLoadingListener listener) {        Listdatas= DataUtil.getInstance().getData();        listener.onComplete(datas);    }}

renyou.com.mvp.view

 
 
MvpView:view层接口
public interface MvpView {    /**     * 显示加载进度     */    void showLoading();    /**     * 显示数据     * @param datas 要显示的数据     */    void showDatas(Listdatas);}

renyou.com.mvp.presenter

MvpPresenterV1:presenter类
public class MvpPresenterV1 {    //view    MvpView mvpView;    //model    MvpModel mvpModel=new MvpModelImplV1();    public MvpPresenterV1(MvpView mvpView){        this.mvpView=mvpView;    }    /**     * bind view and model     */    public void fetch(){        mvpView.showLoading();        if(mvpModel!=null){            mvpModel.loadDatas(new MvpModel.DataOnLoadingListener() {                @Override                public void onComplete(List datas) {                    mvpView.showDatas(datas);                }            });        }    }}

renyou.com.mvp.bean

Renyou:bean类
 
 

public class Renyou {
private String name;

public Renyou(String name){
this.name=name;
}

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

}

renyou.com.mvp.data

DataUtil:加载数据类
public class DataUtil {    private static DataUtil dataUtil=null;    public static DataUtil getInstance(){        if(dataUtil==null){            dataUtil=new DataUtil();        }        return dataUtil;    }    public List getData(){        List datas = new ArrayList<>();        for (int i = 0; i <20; i++) {            Renyou renyou = new Renyou("" + i);            datas.add(renyou);        }        return datas;    }}

renyou.com.mvp.adapter

MvpAdapter:listview适配器
public class MvpAdapter extends BaseAdapter {    private Context context;    private Listdatas;    public MvpAdapter(Context context,Listdatas){        this.cOntext=context;        this.datas=datas;    }    @Override    public int getCount() {        return datas.size();    }    @Override    public Object getItem(int position) {        return datas.get(position);    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        if(cOnvertView==null){            cOnvertView=View.inflate(context, R.layout.item, null);        }        ViewHolder holder=ViewHolder.getHolder(convertView);        holder.tv.setText(datas.get(position).getName());        return convertView;    }    static class ViewHolder{        TextView tv;        public ViewHolder(View convertView){            tv=(TextView) convertView.findViewById(R.id.id_num);        }        public static ViewHolder getHolder(View convertView){            ViewHolder holder=(ViewHolder) convertView.getTag();            if(holder==null){                holder = new ViewHolder(convertView);                convertView.setTag(holder);            }            return holder;        }    }}
我相信有面向对象基础的开发者都可以看的懂上述代码,这里就不一一解释了。

上述mvp代码性能优化

上述代码缺陷:

如图所示:activity/view会持有presenter层的引用,presenter会引用model层的引用。model加载的数据极有可能是网络数据,且极有可能是异步子线程加载的数据。加载这样的数据要耗时,一旦用户点击回退推出了当前的view,则view就被释放了,但是当model层加载数据完成后会回掉监听器,他会拿着view的引用去访问一块已经被释放了的view内存。这样是没有必要的,是浪费资源的,导致了内存的泄漏。

解决方案:

新增的类

MvpBaseActivity基类
public abstract class MvpBaseActivity>extends AppCompatActivity {    protected T mPresenter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mPresenter=createPresenter();        mPresenter.attachView((V)this);    }    @Override    protected void onDestroy() {        super.onDestroy();        mPresenter.detachView();    }    public abstract T createPresenter();}

BasePresenter基类presenter
 
 
public abstract class BasePresenter {    /**     * 当内存不足时释放内存     */    protected WeakReferencemViewRef;    /**     * bind presenter with view     * @param view     */    public void attachView(T view){        mViewRef=new WeakReference(view);    }    /**     * detach view manager     */    public void detachView(){        if(mViewRef!=null){            mViewRef.clear();            mViewRef=null;        }    }    protected T getView(){        return mViewRef.get();    }}

修改的类:
 
 
MvpPresenterV1让它继承基类presenter
public class MvpPresenterV1 extends BasePresenter {    //model    MvpModel mvpModel=new MvpModelImplV1();    /**     * bind view and model     */    public void fetch(){        getView().showLoading();        if(mvpModel!=null){            mvpModel.loadDatas(new MvpModel.DataOnLoadingListener() {                @Override                public void onComplete(List datas) {                    getView().showDatas(datas);                }            });        }    }}

MvpActivity让他继承基类
public class MvpActivity extends MvpBaseActivity implements MvpView{    private ListView listview;    private MvpAdapter mAdapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_mvp);        initView();        mPresenter.fetch();    }    @Override    public MvpPresenterV1 createPresenter() {        return new MvpPresenterV1();    }    private void initView() {        listview= (ListView) findViewById(R.id.lv_main);    }    @Override    public void showLoading() {        Toast.makeText(getApplicationContext(),"正在加载...",Toast.LENGTH_LONG).show();    }    @Override    public void showDatas(List datas) {        mAdapter=new MvpAdapter(getApplicationContext(), datas);        listview.setAdapter(mAdapter);    }}

这样就完美解决了内存泄漏这个令人烦恼的问题。代码读者多多研究,有点难懂。







 
 

 
 
 
 

















推荐阅读
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了在Vue项目中如何结合Element UI解决连续上传多张图片及图片编辑的问题。作者强调了在编码前要明确需求和所需要的结果,并详细描述了自己的代码实现过程。 ... [详细]
  • 标题: ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
author-avatar
知心friend2007
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有