2024年安卓最新一文说透 Android 应用架构 MVC、MVP、MVVM 和 组件化(1),轻松获得一线大厂面试offer

总结

算法知识点繁多,企业考察的题目千变万化,面对越来越近的“金九银十”,我给大家准备好了一套比较完善的学习方法,希望能帮助大家在有限的时间里尽可能系统快速的恶补算法,通过高效的学习来提高大家面试中算法模块的通过率。

这一套学习资料既有文字档也有视频,里面不仅仅有关键知识点的整理,还有案例的算法相关部分的讲解,可以帮助大家更好更全面的进行学习,二者搭配起来学习效果会更好。

部分资料展示:




有了这套学习资料,坚持刷题一周,你就会发现自己的算法知识体系有明显的完善,离大厂Offer的距离更加近。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!


2.1 概念梳理

MVP (Model-View-Presenter) 是MVC的演化版本,几个主要部分如下:

  • 模型层 (Model):主要提供数据存取功能。
  • 视图层 (View):处理用户事件和视图。在Android中,可能是指Activity、Fragment或者View。
  • 展示层 (Presenter):负责通过Model存取书数据,连接View和Model,从Model中取出数据交给View。

所以,对于MVP的架构设计,我们有以下几点需要说明:

  1. 这里的Model是用来存取数据的,也就是用来从指定的数据源中获取数据,不要将其理解成MVC中的Model。在MVC中Model是数据模型,在MVP中,我们用Bean来表示数据模型。
  2. Model和View不会直接发生关系,它们需要通过Presenter来进行交互。在实际的开发中,我们可以用接口来定义一些规范,然后让我们的View和Model实现它们,并借助Presenter进行交互即可。

为了说明MVP设计模式,我们给出一个示例程序。你可以在Github中获取到它的源代码。

2.2 示例程序

在该示例中,我们使用了:

  1. 开眼视频的API作为数据源;
  2. Retrofit进行数据访问;
  3. 使用ARouter进行路由;
  4. 使用MVP设计模式作为程序架构。

下面是该模块的基本的包结构:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里核心的代码是MVP部分。

这里我们首先定义了MVP模式中的最顶层的View和Presenter,在这里分别是BaseViewBasePresenter,它们在该项目中是两个空的接口,在一些项目中,我们可以根据自己的需求在这两个接口中添加自己需要的方法。

然后,我们定义了HomeContract。它是一个抽象的接口,相当于一层协议,用来规定指定的功能的View和Presenter分别应该具有哪些方法。通常,对于不同的功能,我们需要分别实现一个MVP,每个MVP都会又一个对应的Contract。笔者认为它的好处在于,将指定的View和Presenter的接口定义在一个接口中,更加集中。它们各自需要实现的方法也一目了然地展现在了我们面前。

这里根据我们的业务场景,该接口的定义如下:

public interface HomeContract {

interface IView extends BaseView {
void setFirstPage(List<HomeBean.IssueList.ItemList> itemLists);
void setNextPage(List<HomeBean.IssueList.ItemList> itemLists);
void onError(String msg);
}

interface IPresenter extends BasePresenter {
void requestFirstPage();
void requestNextPage();
}
}

HomeContract用来规定View和Presenter应该具有的操作,在这里它用来指定主页的View和Presenter的方法。从上面我们也可以看出,这里的IViewIPresenter分别实现了BaseViewBasePresenter

上面,我们定义了V和P的规范,MVP中还有一项Model,它用来从网络中获取数据。这里我们省去网络相关的具体的代码,你只需要知道APIRetrofit.getEyepetizerService()是用来获取Retrofit对应的Service,而getMoreHomeData()getFirstHomeData()是用来从指定的接口中获取数据就行。下面是HomeModel的定义:

public class HomeModel {

public Observable getFirstHomeData() {
return APIRetrofit.getEyepetizerService().getFirstHomeData(System.currentTimeMillis());
}

public Observable getMoreHomeData(String url) {
return APIRetrofit.getEyepetizerService().getMoreHomeData(url);
}
}

OK,上面我们已经完成了Model的定义和View及Presenter的规范的定义。下面,我们就需要具体去实现View和Presenter。

首先是Presenter,下面是我们的HomePresenter的定义。在下面的代码中,为了更加清晰地展示其中的逻辑,我删减了一部分无关代码:

public class HomePresenter implements HomeContract.IPresenter {

private HomeContract.IView view;

private HomeModel homeModel;

private String nextPageUrl;

// 传入View并实例化Model
public HomePresenter(HomeContract.IView view) {
this.view = view;
homeModel = new HomeModel();
}

// 使用Model请求数据,并在得到请求结果的时候调用View的方法进行回调
@Override
public void requestFirstPage() {
Disposable disposable = homeModel.getFirstHomeData()
// …
.subscribe(itemLists -> { view.setFirstPage(itemLists); },
throwable -> { view.onError(throwable.toString()); });
}

// 使用Model请求数据,并在得到请求结果的时候调用View的方法进行回调
@Override
public void requestNextPage() {
Disposable disposable = homeModel.getMoreHomeData(nextPageUrl)
// …
.subscribe(itemLists -> { view.setFirstPage(itemLists); },
throwable -> { view.onError(throwable.toString()); });
}
}

从上面我们可以看出,在Presenter需要将View和Model建立联系。我们需要在初始化的时候传入View,并实例化一个Model。Presenter通过Model获取数据,并在拿到数据的时候,通过View的方法通知给View层。

然后,就是我们的View层的代码,同样,我对代码做了删减:

@Route(path = BaseConstants.EYEPETIZER_MENU)
public class HomeActivity extends CommonActivity implements HomeContract.IView {

// 实例化Presenter
private HomeContract.IPresenter presenter;
{
presenter = new HomePresenter(this);
}

@Override
protected int getLayoutResId() {
return R.layout.activity_eyepetizer_menu;
}

@Override
protected void doCreateView(Bundle savedInstanceState) {
// …
// 使用Presenter请求数据
presenter.requestFirstPage();
loading = true;
}

private void configList() {
// …
getBinding().rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
// 请求下一页的数据
presenter.requestNextPage();
}
}
});
}

// 当请求到结果的时候在页面上做处理,展示到页面上
@Override
public void setFirstPage(List<HomeBean.IssueList.ItemList> itemLists) {
loading = false;
homeAdapter.addData(itemLists);
}

// 当请求到结果的时候在页面上做处理,展示到页面上
@Override
public void setNextPage(List<HomeBean.IssueList.ItemList> itemLists) {
loading = false;
homeAdapter.addData(itemLists);
}

@Override
public void onError(String msg) {
ToastUtils.makeToast(msg);
}

// …
}

从上面的代码中我们可以看出实际在View中也要维护一个Presenter的实例。 当需要请求数据的时候会使用该实例的方法来请求数据,所以,在开发的时候,我们需要根据请求数据的情况,在Presenter中定义接口方法。

实际上,MVP的原理就是View通过Presenter获取数据,获取到数据之后再回调View的方法来展示数据。

2.3 MVC 和 MVP 的区别

  1. MVC 中是允许 Model 和 View 进行交互的,而MVP中,Model 与 View 之间的交互由Presenter完成;
  2. MVP 模式就是将 P 定义成一个接口,然后在每个触发的事件中调用接口的方法来处理,也就是将逻辑放进了 P 中,需要执行某些操作的时候调用 P 的方法就行了。

2.4 MVP的优缺点

优点:

  1. 降低耦合度,实现了 Model 和 View 真正的完全分离,可以修改 View 而不影响 Modle;
  2. 模块职责划分明显,层次清晰;
  3. 隐藏数据;
  4. Presenter 可以复用,一个 Presenter 可以用于多个 View,而不需要更改 Presenter 的逻辑;
  5. 利于测试驱动开发,以前的Android开发是难以进行单元测试的;
  6. View 可以进行组件化,在MVP当中,View 不依赖 Model。

缺点:

  1. Presenter 中除了应用逻辑以外,还有大量的 View->Model,Model->View 的手动同步逻辑,造成 Presenter 比较笨重,维护起来会比较困难;
  2. 由于对视图的渲染放在了 Presenter 中,所以视图和 Presenter 的交互会过于频繁;
  3. 如果 Presenter 过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密,一旦视图需要变更,那么Presenter也需要变更了。

3、MVVM (分手大师)

3.1 基础概念

MVVM 是 Model-View-ViewModel 的简写。它本质上就是 MVC 的改进版。MVVM 就是将其中的 View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。

  • 模型层 (Model):负责从各种数据源中获取数据;
  • 视图层 (View):在 Android 中对应于 Activity 和 Fragment,用于展示给用户和处理用户交互,会驱动 ViewModel 从 Model 中获取数据;
  • ViewModel 层:用于将 Model 和 View 进行关联,我们可以在 View 中通过 ViewModel 从 Model 中获取数据;当获取到了数据之后,会通过自动绑定,比如 DataBinding,来将结果自动刷新到界面上。

使用 Google 官方的 Android Architecture Components ,我们可以很容易地将 MVVM 应用到我们的应用中。下面,我们就使用它来展示一下 MVVM 的实际的应用。你可以在Github中获取到它的源代码。

3.2 示例程序

在该项目中,我们使用了:

  1. 果壳网的 API 作为数据源;
  2. 使用 Retrofit 进行网络数据访问;
  3. 使用 ViewMdeol 作为整体的架构设计。

该项目的包结构如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里的model.data下面的类是对应于网络的数据实体的,由JSON自动生成,这里我们不进行详细描述。这里的model.repository下面的两个类是用来从网络中获取数据信息的,我们也忽略它的定义。

上面就是我们的 Model 的定义,并没有太多的内容,基本与 MVP 一致。

下面的是 ViewModel 的代码,我们选择了其中的一个方法来进行说明。当我们定义 ViewModel 的时候,需要继承 ViewModel 类。

public class GuokrViewModel extends ViewModel {

public LiveData<Resource> getGuokrNews(int offset, int limit) {
MutableLiveData<Resource> result = new MutableLiveData<>();
GuokrRetrofit.getGuokrService().getNews(offset, limit)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onError(Throwable e) {
result.setValue(Resource.error(e.getMessage(), null));
}

@Override
public void onComplete() { }

@Override
public void onSubscribe(Disposable d) { }

@Override
public void onNext(GuokrNews guokrNews) {
result.setValue(Resource.success(guokrNews));
}
});
return result;
}
}

这里的 ViewModel 来自 android.arch.lifecycle.ViewModel,所以,为了使用它,我们还需要加入下面的依赖:

api “android.arch.lifecycle:runtime: a r c h V e r s i o n " a p i " a n d r o i d . a r c h . l i f e c y c l e : e x t e n s i o n s : archVersion" api "android.arch.lifecycle:extensions: archVersion"api"android.arch.lifecycle:extensions:archVersion”
annotationProcessor “android.arch.lifecycle:compiler:$archVersion”

在 ViewModel 的定义中,我们直接使用 Retrofit 来从网络中获取数据。然后当获取到数据的时候,我们使用 LiveData 的方法把数据封装成一个对象返回给 View 层。在 View 层,我们只需要调用该方法,并对返回的 LiveData 进行"监听"即可。这里,我们将错误信息和返回的数据信息进行了封装,并且封装了一个代表当前状态的枚举信息,你可以参考源代码来详细了解下这些内容。

上面我们定义完了 Model 和 ViewModel,下面我们看下 View 层的定义,以及在 View 层中该如何使用 ViewModel。

@Route(path = BaseConstants.GUOKR_NEWS_LIST)
public class NewsListFragment extends CommonFragment {

private GuokrViewModel guokrViewModel;

分享读者

作者2013年java转到Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。

被人面试过,也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!

我们整理了一份阿里P7级别的Android架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。

主要包括阿里,以及字节跳动,腾讯,华为,小米,等一线互联网公司主流架构技术。如果你有需要,尽管拿走好了。

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

48)]

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值