一文说透 Android 应用架构 MVC、MVP、MVVM 和 组件化
以前一直是自己在网上东平西凑的找,找到的东西也是零零散散,很多时候都是看着看着就没了,时间浪费了,问题却还没得到解决,很让人抓狂。后面我就自己整理了一套资料,还别说,真香!资料有条理,有系统,还很全面,我不方便直接放出来,大家可以先看看有没有用得到的地方吧。《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取
这里的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;
private int offset = 0;
private final int limit = 20;
private GuokrNewsAdapter adapter;
@Override
protected int getLayoutResId() {
return R.layout.fragment_news_list;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
// …
guokrViewModel = ViewModelProviders.of(this).get(GuokrViewModel.class);
fetchNews();
}
private void fetchNews() {
guokrViewModel.getGuokrNews(offset, limit).observe(this, guokrNewsResource -> {
if (guokrNewsResource == null) {
return;
}
switch (guokrNewsResource.status) {
case FAILED:
ToastUtils.makeToast(guokrNewsResource.message);
break;
case SUCCESS:
adapter.addData(guokrNewsResource.data.getResult());
adapter.notifyDataSetChanged();
break;
}
});
}
}
以上就是我们的 View 层的定义,这里我们先使用了
这里的view.fragment包下面的类对应于实际的页面,这里我们 ViewModelProviders 的方法来获取我们需要使用的 ViewModel,然后,我们直接使用该 ViewModel 的方法获取数据,并对返回的结果进行“监听”即可。
以上就是 MVVM 的基本使用,当然,这里我们并没有使用 DataBinding 直接与返回的列表信息进行绑定,它被更多的用在了整个 Fragment 的布局中。
3.3 MVVM 的优点和缺点
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大优点:
- 低耦合:视图(View)可以独立于Model变化和修改,一个 ViewModel 可以绑定到不同的 View 上,当 View 变化的时候 Model 可以不变,当 Model 变化的时候 View 也可以不变。
- 可重用性:你可以把一些视图逻辑放在一个 ViewModel 里面,让很多 view 重用这段视图逻辑。
- 独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
- 可测试:界面素来是比较难于测试的,而现在测试可以针对 ViewModel 来写。
4、组件化
4.1 基础概念
所谓的组件化,通俗理解就是将一个工程分成各个模块,各个模块之间相互解耦,可以独立开发并编译成一个独立的 APP 进行调试,然后又可以将各个模块组合起来整体构成一个完整的 APP。它的好处是当工程比较大的时候,便于各个开发者之间分工协作、同步开发;被分割出来的模块又可以在项目之间共享,从而达到复用的目的。组件化有诸多好处,尤其适用于比较大型的项目。
简单了解了组件化之后,让我们来看一下如何实现组件化开发。你可能之前听说过组件化开发,或者被其高大上的称谓吓到了,但它实际应用起来并不复杂,至少借助了现成的框架之后并不复杂。这里我们先梳理一下,在应用组件化的时候需要解决哪些问题:
- 如何分成各个模块? 我们可以根据业务来进行拆分,对于比较大的功能模块可以作为应用的一个模块来使用,但是也应该注意,划分出来的模块不要过多,否则可能会降低编译的速度并且增加维护的难度。
- 各个模块之间如何进行数据共享和数据通信? 我们可以把需要共享的数据划分成一个单独的模块来放置公共数据。各个模块之间的数据通信,我们可以使用阿里的 ARouter 进行页面的跳转,使用封装之后的 RxJava 作为 EventBus 进行全局的数据通信。
- 如何将各个模块打包成一个独立的 APP 进行调试? 首先这个要建立在2的基础上,然后,我们可以在各个模块的 gradle 文件里面配置需要加载的 AndroidManifest.xml 文件,并可以为每个应用配置一个独立的 Application 和启动类。
- 如何防止资源名冲突问题? 遵守命名规约就能规避资源名冲突问题。
- 如何解决 library 重复依赖以及 sdk 和依赖的第三方版本号控制问题? 可以将各个模块公用的依赖的版本配置到 settings.gradle 里面,并且可以建立一个公共的模块来配置所需要的各种依赖。
Talk is cheap,下面让我们动手实践来应用组件化进行开发。你可以在Github中获取到它的源代码。
4.2 组件化实践
包结构
首先,我们先来看整个应用的包的结构。如下图所示,该模块的划分是根据各个模块的功能来决定的。图的右侧白色的部分是各个模块的文件路径,我推荐使用这种方式,而不是将各个模块放置在 app 下面,因为这样看起来更加的清晰。为了达到这个目的,你只需要按照下面的方式在 settings.gralde 里面配置一下各个模块的路径即可。注意在实际应用的时候模块的路径的关系,不要搞错了。

然后,我们介绍一下这里的 commons 模块。它用来存放公共的资源和一些依赖,这里我们将两者放在了一个模块中以减少模块的数量。下面是它的 gradle 的部分配置。这里我们使用了 api 来引入各个依赖,以便在其他的模块中也能使用这些依赖。
dependencies {
api fileTree(include: [‘*.jar’], dir: ‘libs’)
// …
// router
api ‘com.alibaba:arouter-api:1.3.1’
annotationProcessor ‘com.alibaba:arouter-compiler:1.1.4’
// walle
api ‘com.meituan.android.walle:library:1.1.6’
// umeng
api ‘com.umeng.sdk:common:1.5.3’
api ‘com.umeng.sdk:analytics:7.5.3’
api files(‘libs/pldroid-player-1.5.0.jar’)
}
路由
接着,我们来看一下路由框架的配置。这里,我们使用阿里的 ARouter 来进行页面之间的跳转,你可以在Github上面了解该框架的配置和使用方式。这里我们只讲解一下在组件化开发的时候需要注意的地方。注意到 ARouter 是通过注解来进行页面配置的,并且它的注解是在编译的时候进行处理的。所以,我们需要引入arouter-compiler来使用它的编译时处理功能。需要注意的地方是,我们只要在公共的模块中加入arouter-api就可以使用ARouter的API了,但是需要在每个模块中引入arouter-compiler才能使用编译时注解。也就是说,我们需要在每个模块中都加入arouter-compiler依赖。
模块独立
最后
以前一直是自己在网上东平西凑的找,找到的东西也是零零散散,很多时候都是看着看着就没了,时间浪费了,问题却还没得到解决,很让人抓狂。
后面我就自己整理了一套资料,还别说,真香!
资料有条理,有系统,还很全面,我不方便直接放出来,大家可以先看看有没有用得到的地方吧。






《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
-1715032750543)]
[外链图片转存中…(img-VggG59HC-1715032750545)]
[外链图片转存中…(img-ce1oZXTN-1715032750546)]
[外链图片转存中…(img-c7XEIR2Z-1715032750548)]
[外链图片转存中…(img-Zs7oOe4z-1715032750549)]
[外链图片转存中…(img-dFENv1HE-1715032750551)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
更多推荐


所有评论(0)