揭秘Android应用架构:深度解读与实战经验分享

更新:11-01 名人轶事 我要投稿 纠错 投诉

其实揭秘Android应用架构:深度解读与实战经验分享的问题并不复杂,但是又很多的朋友都不太了解,因此呢,今天小编就来为大家分享揭秘Android应用架构:深度解读与实战经验分享的一些知识,希望可以帮助到大家,下面我们一起来看看这个问题的分析吧!

前言

Android架构可能是论坛上讨论最多的话题。经常听到MVC mvp和mvvm,其次是模块化和插件化。对此,关于哪种架构更好的争论从未停止过。

我的观点:没有实际项目来比较这些模式的优劣是没有意义的。每种模型都有优点和缺点,没有好坏之分。架构越先进,实现起来就越复杂,需要更多的学习成本和更多的人力。因此,技术选型的关键是自己项目的特点、团队的水平、资源的配置以及开发时间的限制。这些才是重点!然而很多团队本末倒置,将mvvm应用到自己的项目中。

接下来我会从代码层面两大部分来谈谈我对Android架构的理解,主要是对MVC和MVP的理解。在项目层面,主要关注如何构建整个项目以及如何将其划分为模块。

通俗理解MVC和MVP

先说结论:

MVC:模型-视图-控制器,经典模式,很容易理解。它有两个主要缺点:View对Model的依赖会导致View也包含业务逻辑;控制器将变得非常厚重和复杂。 MVP:Model-View-Presenter,MVC的一种演化模型,用Presenter代替Controller,主要是为了解决上面提到的第一个缺点,解耦View和Model,但是第二个缺点仍然没有解决。 MVVM:Model-View-ViewModel是MVP的一种优化模式,采用双向绑定:View中的变化会自动反映在ViewModel中,反之亦然。

MVC

简单来说:我们平时写的demo都是MVC,controller是我们的activity,model(数据提供者)是读取数据库,我们通常有专门的类来处理网络请求,View一般使用自定义控制。

但这一切只是看起来很美丽。

想象一下,在实际开发中,我们的活动代码其实是越来越多,模型和控制器根本没有分离,而且控件也需要关系数据和业务。

所以,MVC真正的存在是MC(V),Model和Controller根本无法分离,数据和View严重耦合。这就是它的问题所在。举个简单的例子:获取天气数据并显示在界面上

image.pngModel层公共接口WeatherModel {

void getWeather(String cityNumber, OnWeatherListener 监听器);

}

…………

公共类WeatherModelImpl 实现WeatherModel {

@覆盖

公共无效getWeather(字符串城市编号,最终OnWeatherListener 侦听器){

/*数据层操作*/

VolleyRequest.newInstance().newGsonRequest(http://www.weather.com.cn/data/sk/+ cityNumber + .html,

Weather.class, new Response.Listener() {

@覆盖

公共无效onResponse(天气天气){

如果(天气!=null){

监听器.onSuccess(天气);

} 别的{

监听器.onError();

}

}

}, 新的Response.ErrorListener() {

@覆盖

公共无效onErrorResponse(VolleyError错误){

监听器.onError();

}

});

}

}控制(视图)层

公共类MainActivity扩展ActionBarActivity实现OnWeatherListener,View.OnClickListener {

私人WeatherModel天气模型;

私人EditText cityNOInput;

私人TextView 城市;

.

@覆盖

protected void onCreate(Bundle savingInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

天气模型=新的WeatherModelImpl();

初始化视图();

}

//初始化视图

私有无效initView() {

cityNOInput=findView(R.id.et_city_no);

城市=findView(R.id.tv_city);

.

findView(R.id.btn_go).setOnClickListener(this);

}

//显示结果

公共无效displayResult(天气天气){

WeatherInfo 天气信息=天气.getWeatherinfo();

city.setText(weatherInfo.getCity());

.

}

@覆盖

公共无效onClick(查看v){

开关(v.getId()) {

案例R.id.btn_go:

WeatherModel.getWeather(cityNOInput.getText().toString().trim(), this);

休息;

}

}

@覆盖

公共无效onSuccess(天气天气){

显示结果(天气);

}

@覆盖

公共无效onError() {

Toast.makeText(this,获取天气信息失败,Toast.LENGTH_SHORT).show();

}

私人T findView(int id) {

返回(T)findViewById(id);

}

我们简单分析一下这个例子:

1. Activity中的控件必须关心业务和数据,然后才知道如何展示。也就是说,我们很难有两个人,一个负责获取数据,一个负责显示UI,在互相不沟通的情况下完成这个功能。

2.所有逻辑都在活动中。

它完美地体现了MVC的两大缺点。我们看看MVP是如何解决第一个缺点的。

MVP

image.png 从上图可以看出,MVC中View被拆分为Presenter和View,真正实现了逻辑处理与View的分离。下面写一个例子:模拟一个登录界面,输入用户名和密码,即可登录并清除密码

模型层/**

定义业务接口

*/

公共接口IUserBiz

{

公共无效登录(字符串用户名,字符串密码,OnLoginListener登录监听器);

}

/**

结果回调接口

*/

公共接口OnLoginListener

{

无效登录成功(用户用户);

无效登录失败();

}

/**

具体模型的实现

*/

公共类UserBiz 实现IUserBiz

{

@覆盖

公共无效登录(最终字符串用户名,最终字符串密码,最终OnLoginListener登录监听器)

{

//模拟子线程的耗时操作

新线程()

{

@覆盖

公共无效运行()

{

尝试

{

线程睡眠(2000);

} catch (InterruptedException e)

{

e.printStackTrace();

}

//模拟登录成功

if ("zhy".equals(用户名) "123".equals(密码))

{

用户用户=新用户();

user.setUsername(用户名);

用户.setPassword(密码);

登录监听器.loginSuccess(用户);

} 别的

{

登录监听器.loginFailed();

}

}

}。开始();

}

}看法

如上所述,View层是以接口的形式定义的。我们不关心数据或逻辑处理!我们只关心和用户的交互,所以这个登录界面应该有的操作有(把这个界面想象成一个容器,有输入和输出):获取用户名、获取密码、显示进度条、隐藏进度条、跳转到其他界面,显示失败对话框,清除用户名,清除密码。接下来定义接口:

公共接口IUserLoginView

{

字符串getUserName();

字符串getPassword();

无效清除用户名();

无效清除密码();

无效显示加载();

无效隐藏加载();

无效toMainActivity(用户用户);

无效showFailedError();

}然后Activity实现这个接口:

公共类UserLoginActivity 扩展ActionBarActivity 实现IUserLoginView

{

私有EditText mEt用户名,mEt密码;

私有按钮mBtnLogin、mBtnClear;

私有进度条mPbLoading;

私有UserLoginPresenter mUserLoginPresenter=new UserLoginPresenter(this);

@覆盖

protected void onCreate(Bundle savingInstanceState)

{

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_user_login);

初始化视图();

}

私有无效initViews()

{

mEtUsername=(EditText) findViewById(R.id.id_et_username);

mEtPassword=(EditText) findViewById(R.id.id_et_password);

mBtnClear=(按钮) findViewById(R.id.id_btn_clear);

mBtnLogin=(按钮) findViewById(R.id.id_btn_login);

mPbLoading=(ProgressBar) findViewById(R.id.id_pb_loading);

mBtnLogin.setOnClickListener(new View.OnClickListener()

{

@覆盖

公共无效onClick(查看v)

{

mUserLoginPresenter.login();

}

});

mBtnClear.setOnClickListener(new View.OnClickListener()

{

@覆盖

公共无效onClick(查看v)

{

mUserLoginPresenter.clear();

}

});

}

@覆盖

公共字符串getUserName()

{

返回mEtUsername.getText().toString();

}

@覆盖

公共字符串getPassword()

{

返回mEtPassword.getText().toString();

}

@覆盖

公共无效清除用户名()

{

mEtUsername.setText("");

}

@覆盖

公共无效清除密码()

{

mEtPassword.setText("");

}

@覆盖

公共无效显示加载()

{

mPbLoading.setVisibility(View.VISIBLE);

}

@覆盖

公共无效隐藏加载()

{

mPbLoading.setVisibility(View.GONE);

}

@覆盖

公共无效toMainActivity(用户用户)

{

Toast.makeText(this, user.getUsername() +

"登录成功,进入MainActivity", Toast.LENGTH_SHORT).show();

}

@覆盖

公共无效showFailedError()

{

Toast.makeText(这个,

"登录失败", Toast.LENGTH_SHORT).show();

}

}主持人

Presenter的作用就是从View层获取用户输入,传递给Model层处理,然后回调到View层输出给用户!公共类UserLoginPresenter

{

私有IUserBiz 用户Biz;

私有IUserLoginView userLoginView;

私有处理程序mHandler=new Handler();

//Presenter必须能够获取View和Model的实现类

公共UserLoginPresenter(IUserLoginView userLoginView)

{

this.userLoginView=userLoginView;

this.userBiz=new UserBiz();

}

公共无效登录()

{

userLoginView.showLoading();

userBiz.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener()

{

@覆盖

公共无效登录成功(最终用户用户)

{

//需要在UI线程上执行

mHandler.post(new Runnable())

{

@覆盖

公共无效运行()

{

userLoginView.toMainActivity(用户);

userLoginView.hideLoading();

}

});

}

@覆盖

公共无效登录失败()

{

//需要在UI线程上执行

mHandler.post(new Runnable())

{

@覆盖

公共无效运行()

{

userLoginView.showFailedError();

userLoginView.hideLoading();

}

});

}

});

}

公共无效清除()

{

userLoginView.clearUserName();

userLoginView.clearPassword();

}

}分析这个例子:

1.我们有IUserLoginView接口(协议)。活动中的控件根本不需要关心数据。他们只需要实现这个接口就可以在每个方法中“一步步”显示UI。也就是说,我们让两个人一起开发这个功能。一个人要处理数据并制定接口(协议),另一个人直接使用活动来实现接口。 UI可以在每次回调中闭着眼睛显示。合作非常愉快。

2、MVP成功解决了MVC的第一个缺点,但逻辑处理仍然混杂在Activity中。

简单来说,MVC 到MVP 就是增加一个接口,减少一层耦合。那么,用MVP来MVVM只是增加一个接口而已。对于实际项目,我建议使用MVP模型。 MVVM 还是很复杂,对于中小型项目来说有点过度设计,所以这里不再赘述。

模块化

图像.png

上图是一个项目的常见架构

1.最底层是基础库,放置与业务无关的模块:如基础网络请求、图像压缩等,可分为逻辑模块、通用UI模块和第三方库根据需要。 (建议使用独立的svn分支)

2、中间层为通用业务层,容纳了公司多个Android项目的通用业务模块(业务相关),如登录流程、文件上传/下载等。

3、最上层是应用层。例如,公司有三个android项目:LbBoss、BV和BVHD。我们还可以为类似的项目提取一个公共层(比如这里的BV和BV PAD版本,公共层就是BVCommon)。

在创建一个新的App时,我们常常有两种模块划分的方法:

按类型分:

image.png按照业务划分:

每个包就是一个业务模块,每个模块按照类型进行划分。如何选择

我建议对于中小型的新项目,最好按照类型来划分,因为一开始代码量并不大,按照业务来划分是不现实的。一个包中可以放置多少个文件?而且,早期业务不稳定。一旦业务在开发过程中定型,重构就不是什么难事。上面提到的模块划分既不是模块化也不是插件化。只是简单的封装结构有所不同。该应用程序仍然是一个应用程序,没有任何变化。一般来说,模块化是指将业务划分为不同的模块(type为library),各个模块之间互不依赖,而app(type为application)只是一个依赖所有模块的空壳。

图片.png

每个红色箭头都是一个业务模块,红框内是我们的app只包含简单的业务:自定义Application、入口Activity、build.gradle编译和打包配置。查看项目的依赖关系:

这样的架构之后,最大的区别就是不同的业务模块是完全分离的。这样做的好处是,不同模块的开发永远不会相互耦合,因为在模块A中根本无法访问模块B的API,这时候就迫切需要解决模块之间的通信。 Intent隐式跳转可以处理一些Activity的跳转,但真正的业务场景远不止两个接口。之前你封装的常用业务方法、工具类、数据缓存,现在其他模块都无法使用了。本来可以复用的控件和片段无法共享,而且这些与业务是耦合的,无法从底层基础库访问。

模块间通信

针对上述问题有两种解决方案。根据你项目的实际情况,如果项目前期已经很优秀,有完整的基础库,不同模块之间没有太多的沟通,你可以自己实现。如果项目比较大,不同业务之间调用频繁,建议使用阿里巴巴的开源库。

自己意识到

1.首先,每个模块都有一个名为include的目录,其中包含三个类。这里我们以bbs论坛模块为例。

IBBSNotify:里面有一堆接口,作为模块的外部回调,只能被动触发。

IBBService:里面有一堆接口,用来向外界暴露方法,让其他模块主动调整,比如enterBbsActivity。

IBBSServiceImpl:显然是IBBService的实现。比如enterBbsActivity是如何跳转到论坛界面,传递什么数据。图片.png

2.每个模块都有方法和回调,包括in和out。如何使用其他模块?是时候该应用程序登场了。该应用程序不能只是一个外壳。需要定义一个ModulatorManager实现所有模块的对外接口。作为各个模块的中转站,模块A告诉ModulatorManager我要跳转到论坛模块,然后ModulatorManager调用IBBService.enterBbsActivity。IBBSServiceImpl是IBBService的具体实现(多态)然后调用IBBSServiceImpl.enterBbsActivity跳转到BBS界面。

3、沟通解决了,但其实陷阱才刚刚开始:

一个。这里的app是我们新创建的,所以需要将之前项目的app模块缩减为library:

应用plugin:"com.android.library"shell应用程序的build.gradle配置:

apply plugin: “com.android.application”的性质发生了巨大的变化。自定义应用程序、build.gradle、代码混淆配置等全部移至应用程序中

b.R.java在Lib类型模块中不是final的。所有switch case 语句都替换为if else。

c.一定要再建一个公共模块来放置公共数据、缓存等。

d.还有很多常用的功能,比如分享、推送等。尝试剥离业务并将其纳入共同点

e.其他与项目相关的细节

开源库ARouter

专门用于连接模块之间的通信。这里就不说了,使用起来也很简单。

其他

插件:

其实插件发布的最终产品也是一个apk,只不过大小是可以控制的(可以随意去掉一些模块),并且用户可以动态加载子apk。所以,插件就是动态加载apk。有人说我用intent可以直接隐式跳转到另一个apk,那为什么还需要插件呢?

揭秘Android应用架构:深度解读与实战经验分享的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于、揭秘Android应用架构:深度解读与实战经验分享的信息别忘了在本站进行查找哦。

用户评论

弃我者亡

终于有人聊聊框架结构了!我一直对Android开发有点困惑。

    有7位网友表示赞同!

一个人的荒凉

我也很感兴趣,想看看你用的那种架构

    有15位网友表示赞同!

折木

分享一下你常用的架构设计方法呗?

    有12位网友表示赞同!

哭花了素颜

架构很重要啊,能解决很多问题

    有18位网友表示赞同!

陌上花

我最近也在学习Android开发,这篇文章很有用!

    有6位网友表示赞同!

瑾澜

期待看到一篇深入浅出的讲解!

    有11位网友表示赞同!

我的黑色迷你裙

Android的架构确实挺复杂的,总希望能找到一套适合自己的!

    有17位网友表示赞同!

独角戏°

有没有一些典型的例子可以参考?

    有6位网友表示赞同!

命该如此

我比较喜欢MVP/MVVM这种风格,方便维护,你用过吗?

    有8位网友表示赞同!

艺菲

你的理解和我的想法可能类似,期待交流!

    有5位网友表示赞同!

清原

学习架构设计需要不断摸索和实践,加油!

    有19位网友表示赞同!

*巴黎铁塔

分享一下遇到的坑吧,避免我走弯路!

    有5位网友表示赞同!

素颜倾城

不同的项目场景下,架构选择应该有所区别吗?

    有13位网友表示赞同!

一别经年

你的文章能帮助很多初学者入门Android领域!

    有7位网友表示赞同!

虚伪了的真心

感觉你对Android开发很有经验呀!

    有5位网友表示赞同!

疲倦了

希望能够看到更丰富的例子和讨论!

    有10位网友表示赞同!

半世晨晓。

这篇文章让我对Android架构有了新的认识。

    有14位网友表示赞同!

剑已封鞘

我正在探索一种新的架构设计,可以跟你分享一下想法吗?

    有16位网友表示赞同!

棃海

期待后续更新!

    有9位网友表示赞同!

【揭秘Android应用架构:深度解读与实战经验分享】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活

上一篇:C#编程教程:数据结构基础篇(上) 下一篇:2024抖音极速版官方邀请码获取指南