如何更高效的使用MVP以及官方MVP架构解析

只要用过mvp这个问题可能很多人都知道。写mvp的时候,presenter会持有view,如果presenter有后台异步的长时间的动作,比如网络请求,这时如果返回退出了Activity,后台异步的动作不会立即停止,这里就会有内存泄漏的隐患,所以会在presenter中加入一个销毁view的方法。现在就在之前的项目中做一下修改

//presenter中添加mvpView 置为null的方法

public void onDestroy(){

mvpView = null;

}

//退出时销毁持有Activity

@Override

protected void onDestroy() {

mvpPresenter.onDestroy();

super.onDestroy();

}

presenter中增加了类似的生命周期的方法,用来在退出Activity的时候取消持有Activity。

但是在销毁后需要思考一点,后台的延时操作返回时,这个时候view被销毁了,如果接着去调用view的方法就 会抛出空指针异常。所以在后台的延时操作中需要考虑到这种可能产生空指针的情况,尤其是网络请求。

BasePresenter

如果每一个Activity都需要做绑定和解绑操作就太麻烦了,现在我希望可以有一个通用的presenter来为我们添加view的绑定与销毁。

public abstract class BasePresenter {

public T mView;

public void attach(T mView) {

this.mView = mView;

}

public void dettach() {

mView = null;

}

}

因为不能限定死传入的View,所以使用泛型来代替传入的对象。通过这个通用的presenter我就可以把原来的MvpPresenter简化成下面的样子

public class NewMvpPresenter extends BasePresenter {

private RequestBiz requestBiz;

private Handler mHandler;

public NewMvpPresenter() {

requestBiz = new RequestBiziml();

mHandler = new Handler(Looper.getMainLooper());

}

public void onResume(){

requestBiz.requestForData(new OnRequestListener() {

@Override

public void onSuccess(final List data) {

mHandler.post(new Runnable() {

@Override

public void run() {

mView.hideLoading();

mView.setListItem(data);

}

});

}

@Override

public void onFailed() {

mView.showMessage(“请求失败”);

}

});

}

public void onItemClick(int position){

mView.showMessage(“点击了item”+position);

}

}

BaseView

界面需要提供的UI方法中会有很多类似的UI方法,可以把它们提取到一个公共的父类接口中。比如提取显示loading界面和隐藏loading界面的方法,其他的view层接口就可以直接继承BaseView接口,不必重复的写显示和隐藏loading界面方法。

public interface BaseView {

void showLoading();

void hideLoading();

}

BaseMvpActivity

presenter绑定到activity和View的绑定和解绑操作是每个Activity都会去做的,同样这里我也希望能有一个父类来完成这个统一的操作。

public abstract class BaseMvpActivity<V,T extends BasePresenter> extends AppCompatActivity {

public T presenter;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

presenter = initPresenter();

}

@Override

protected void onResume() {

super.onResume();

presenter.attach((V)this);

}

@Override

protected void onDestroy() {

presenter.dettach();

super.onDestroy();

}

// 实例化presenter

public abstract T initPresenter();

}

同样使用泛型来提取通用的逻辑,presenter的初始化,以及view的绑定和解绑操作都提取到父类Activity中。向外部提供了一个 initPresenter(); 方法用来初始化presenter,如果想创建不同参数的构造函数都可以随意去创建。

更加通用的例子

通过上面的base父类,对之前的例子进行优化,写一个更加好用的例子。

NewMvpView 继承BaseView接口,添加自己的初始化ListView和Toast信息方法

public interface NewMvpView extends BaseView {

void setListItem(List data);

void showMessage(String message);

}

NewMvpPresenter 继承BasePresenter类,增加网络请求和处理点击事件的方法

public class NewMvpPresenter extends BasePresenter {

private RequestBiz requestBiz;

private Handler mHandler;

public NewMvpPresenter() {

requestBiz = new RequestBiziml();

mHandler = new Handler(Looper.getMainLooper());

}

public void onResume(){

requestBiz.requestForData(new OnRequestListener() {

@Override

public void onSuccess(final List data) {

mHandler.post(new Runnable() {

@Override

public void run() {

mView.hideLoading();

mView.setListItem(data);

}

});

}

@Override

public void onFailed() {

mView.showMessage(“请求失败”);

}

});

}

public void onItemClick(int position){

mView.showMessage(“点击了item”+position);

}

}

NewMvpActivity

public class NewMvpActivity extends BaseMvpActivity<NewMvpView,NewMvpPresenter> implements NewMvpView,AdapterView.OnItemClickListener{

ListView mvpListView;

ProgressBar pb;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_mvp);

mvpListView = (ListView)findViewById(R.id.mvp_listview);

mvpListView.setOnItemClickListener(this);

pb = (ProgressBar) findViewById(R.id.mvp_loading);

}

@Override

protected void onResume() {

super.onResume();

presenter.onResume();

}

@Override

public NewMvpPresenter initPresenter() {

return new NewMvpPresenter();

}

@Override

public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

presenter.onItemClick(position);

}

@Override

public void setListItem(List data) {

ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,data);

mvpListView.setAdapter(adapter);

}

@Override

public void showMessage(String message) {

Toast.makeText(this,message,Toast.LENGTH_SHORT).show();

}

@Override

public void showLoading() {

pb.setVisibility(View.VISIBLE);

}

@Override

public void hideLoading() {

pb.setVisibility(View.GONE);

}

}

最终的成果,我们只需要在Acitivity中传入泛型对象,并写好initPresenter() Presenter的初始化的方法就可以直接去使用presenter,当然View的接口还是要自己去实现。

以上的方法只是一些比较简单的封装,下面来看看官方的MVP架构是怎么写的。

官方的MVP架构

先来看看官方的代码目录(这里只是功能模块的目录,不包括测试模块,毕竟这里分析的是官方的实现代码)

谷歌的todomvp工程实现了一个类似记事本的功能,整体的目录结构:

tasks 包可以显示任务列表

taskdetail包显示任务详情

addedittask包添加和编辑任务

statistics包用来显示任务的完成情况

data包数据模块对应mvp的M

Util包就是通用的方法。

这里todomvp也有BasePresenter和BaseView2个基类,不过看的出来这2个都是接口。先来看看这2个接口

public interface BasePresenter {

void start();

}

public interface BaseView {

void setPresenter(T presenter);

}

各自简单的声明了一个方法,start()方法用来给Presenter做一些初始化的操作不用特别在意,BaseView声明的方法就很有意思了,setPresenter(T presenter) 很明显是给View绑定Presenter,而前文我们使用的方式给Presenter传入View的方式来完成View和Presenter绑定的操作,这里谷歌采用了相反的方式来操作,为什么呢?

先把这个问题留下,看看单个模块的具体的文件结构。

有Activity,Fragment,Presenter,View哪里去了? 其实谷歌的mvp是将Fragment作为View层来实现的,这一点在官方的Readme中也有说明,为什么要用Fragment?

官方认为Fragement和Activity相比更像是MVP中的的View层,刚好可以满足MVP的View层的要求,Activity则作为最高指挥官用来创建和联系View和Presenter。

Fragment在平板或者屏幕上有多个View时更有优势

Activity只作为创建和联系View和PresenterView而存在,将Fragment作为显示UI而存在。Activity主指挥,Fragment主显示。这也是谷歌的sample中的一贯做法。

View的问题解释完了,再看看TaskDetailContract 这种**Contract 接口,这也是官方独有的管理方法

Contract

google的todomvp 工程中每个模块都会有一个 **Contract 接口,来看看他的代码

public interface TaskDetailContract {

interface View extends BaseView {

void setLoadingIndicator(boolean active);

void showMissingTask();

void hideTitle();

void showTitle(String title);

void hideDescription();

void showDescription(String description);

void showCompletionStatus(boolean complete);

void showEditTask(String taskId);

void showTaskDeleted();

void showTaskMarkedComplete();

void showTaskMarkedActive();

boolean isActive();

}

interface Presenter extends BasePresenter {

void editTask();

void deleteTask();

void completeTask();
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

学习福利

【Android 详细知识点思维脑图(技能树)】

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

(img-fTkI0Jta-1713545962162)]

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

[外链图片转存中…(img-NXGGPeTr-1713545962163)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值