Android 开发月薪 10K 与 30K 之间,只相差这几样热门的前沿知识
M(Model)层:实体模型,处理
业务逻辑
。如:数据库操作,网络操作,I/O 操作,复杂操作和耗时任务等。V(View)层:负责
View的绘制以及与用户交互
。在 Android 开发中,它一般对应着 xml 布局文件和 Activity/Fragment。P(Presenter)层:负责完成 Model 层和 View 层间的数据
交互
和业务逻辑
。
(2) 实例
(3) MVC 和 MVP 的区别
MVP 中的 View 并不直接使用 Model,它们之间的通信是通过 Presenter 来进行的,所有的交互都发生在 Presenter 内部,而在 MVC 中 View 会直接从 Model 中读取数据而不通过 Controller
MVC 和 MVP 的最大区别:MVC 的 Model 层和 View 层
能够直接交互
;MVP 的 Model 层和 View 层不能直接交互
,需通过 Presenter 层来进行交互。Activity 职责不同:Activity 在 MVC 中属于 Controller 层,在 MVP 中属于 View 层,这是 MVC 和 MVP 很主要的一个区别。可以说 Android 从 MVC 转向 MVP 开发也主要是
优化Activity的代码,避免Activity的代码臃肿庞大
。View 层不同:MVC 的 View 层指的是 XML 布局文件(或用 Java 自定义的 View);MVP 的 View 层是 Activity(或 Fragment)
控制层不同:MVC 的控制层是 Activity(或 Fragment);MVP 的控制层是 Presenter,里面没有很多的实际东西,主要负责 Model 层和 View 层的交互。
(4) MVP 优缺点
MVP 的优点如下:
模型与视图完全分离,我们可以修改视图而不影响模型;项目代码结构清晰,一看就知道什么类干什么事情;我们可以将一个 Presenter 用于多个视图,而不需要改变 Presenter 的逻辑,这个特性非常的有用,因为视图的变化总是比模型的变化更频繁 ;协同工作(例如在设计师没出图之前可以先写一些业务逻辑代码)
MVP 也有不足之处:
接口过多,一定程度影响了编码效率。一定程度上导致 Presenter 的代码量过大。为了降低 Presenter 中业务繁多的问题,Google 又推出了 MVVM,试图通过数据驱动来减少 Presenter 的代码量。
1.3 架构设计模式-MVVM
(1) 定义
M(Model)层:仍然是
实体模型
(但是不同于之前定义的 Model 层),主要负责数据获取、存储和变化,提供数据接口供 ViewModel 层调用。V(View)层:对应
Activity/Feagment
和xml布局
文件 ,负责 View 的绘制以及与用户交互说明:View 层仅能操作 UI(数据绑定来实现 UI 更新);不能做任何和业务逻辑有关的数据操作VM(ViewModel)层:负责完成 Model 层和 View 层间的数据
交互
和业务逻辑
说明:ViewModel 层仅能做和业务逻辑有关的数据操作;不能做 UI 相关的操作
2. android 插件化
插件化来由:随着业务的增多,业务逻辑代码越来越多,apk 包也逐渐增大,不利于维护和升级。通过插件化开发可将功能模块解耦,不同的维护团队仅维护某模块的业务,同时当 app 升级时可仅对某功能模块进行升级而不需整体升级。
2.1 插件化要解决的问题—如何动态加载 apk
(1) android 类加载器及区别
类加载器作用:java 字节码通过类加载器加载到 java 虚拟器。
PathClassLoader:仅能加载文件目录下的 apk。
DexClassLoader:可以加载 apk 文件中的字节码(从 dex 实体 jar 文件中加载 java 字节码)。主要用于动态加载和代码热更新等。
(2)反射: java 中的反射使我们在运行时获得这个类的属性、方法和 class 内部的信息机制,最重要的是我们可以在运行时实例化这个对象调用方法,这也是 java 反射的最大优点。(3) 实现动态加载 apk
什么是动态加载 apk:android 中有一个速度程序会主动到指定的 sd 卡中去加载 apk,并通过代理 activity 去执行。
实现:需要一个代理 activity 去执行 apk 中的 activity,主要通过反射去获得它的属性和方法,从而进行 apk 的调用。实现原理:类加载器
(加载类)+反射
(获取属性和方法)+动态代理
(执行)
如:
2.2 插件化要解决的问题—如何加载资源
通过 android 中 ServiceManager 类的隐藏方法来加载资源。
2.3 插件化要解决的问题—如何加载代码
使用 java 中的类加载机制,但是 android 和 java 也
有一点不一样,android 比 java 多了组件和生命周期,所以并不是类加载进来就能使用(不能管理生命周期)。
3. Android 热更新(在线热修复技术)
(1) 热更新流程
检测到线上严重的 crash(参考:app 检测 crash 并发送日志到服务器的实现)
线上版本拉出 bugfix 分支并在分支上修复问题
jenkins 构建及生成补丁
app 在合适时机通过推送或主动拉取补丁文件
将 bugfix 代码合并到 master 上
(2) 热更新主流框架
Dexposed
AndFix
NuWa
(3) 热更新原理
Android 类加载机制(类加载器)
PathClassLoader 类:用来加载系统类 DexClassLoader:用来加载 dex 文件、jar 文件包和 apk 包等
热修复机制(原理)
原理:在 ClassLoader 中创建一个 dexElements 数组,根据线上的 crash 定位找到对应的类文件,然后把这个类文件修复完成后打包成一个 dex 文件并放到 dexElements 数组的最前方。那么当 ClassLoader 遍历 dexElements 数组(加载数组中的 dex 文件)时,因为 ClassLoader 会优先加载最前方的 dex 文件,所以不会加载线上有 crash 的 dex 文件,只会加载修复完的 dex 文件,从而完成热修复过程。
4. Android 进程保活
(1) 进程保活概念
进程保活:让进程在
内存
中永远存在且无法杀死,就算被杀死也能保活。进程被杀死的原因:人为地调用 kill;被第三方安全软件杀死。
进程保活并非是一种流氓手段,在很多场景下我们需要一个常驻进程来为用户提供服务,如:
接收屏幕开关的系统广播:因为广播接收者不支持静态注册,必须在进程中动态注册广播接收者来接收,如果没有常驻进程,那么锁屏应用无法为用户正常提供服务。
定位服务:需要在后台维护一个长连接,以便及时地将信息(推送的信息/定位信息等)传达给用户。
缺点:进程保活在内存,不管如何优化,或多或少都会增加性能的开销。所以需在
进程保活
和内存消耗
之间寻找平衡点来为用户进程保活。
(2) android 进程优先级和回收策略
android 进程优先级:前台进程 > 可见进程 > 服务进程 > 后台进程 > 空进程
android 进程的回收策略:主要依靠 LMK ( Low Memory Killer )机制来完成。LMK 机制通过 oom_adj 这个阀值来判断进程的优先级,oom_adj 的值越高,优先级越低,越容易被杀死。
拓展
:LMK ( Low Memory Killer ) 机制基于 Linux 的 OOM(Out Of Memery)机制,通过一些比较复杂的评分机制,对进程进行打分,将分数高的进程判定为 bad 进程,杀死并释放内存。LMS 机制和 OOM 机制的不同之处在于:OOM 只有当系统内存不足时才会启动检查,而 LMS 机制是定时进行检查。
(3) android进程保活方案
利用系统广播拉活
在发生系统事件时,系统会发出相对响应的广播(常用的广播事件如:开机、网络状态变化、文件或 sd 卡的卸载等),我们可以在 mainfest.xml 文件中静态注册广播监听器缺点(无法拉活的情形):广播接收者被管理软件或系统软件通过自启动管理等功能禁用的场景下是无法接受广播的,从而无法自启动进行系统拉活;系统广播事件是不可控制的,只有在发生事件时才能进行拉活,无法保证进程被杀死后立即被拉活。
利用系统 Service 机制拉活
将 Service 中的 onStartCommand()回调方法的返回值设为
START_STICKY
,就可以利用系统机制在 Service 挂掉后自动拉活。拓展:onStartCommand()的返回值表明当 Service 由于系统内存不足
而被系统杀掉之后,在未来的某个时间段内当系统内存足够的情况下,系统会尝试创建这个 Service,一旦创建成功就又会回调 onStartCommand()方法。缺点(无法拉活的情形):Service 第一次被异常杀死后会在 5s 内重启,第二次会在 10s 内重启,第三次会在 20s 内重启,若 Service 在短时间内被杀死的次数超过 3 次以上系统就会不惊醒拉活;进程被取得 root 权限的管理工具或系统工具通过强制 stop 时,通过 Service 机制无法重启进程。
利用 Native 进程拉活
思想:利用 Linux 中的 fork 机制创建一个 Native 进程,在 Native 进程可以监控主进程的存活,当主进程挂掉之后,Native 进程可以立即对主进程进行拉活。在 Native 进程中如何监听主进程被杀死:可在 Native 进程中通过死循环或定时器,轮询地判断主进程被杀死,但是此方案会耗时耗资源;在主线程中创建一个监控文件,并且在主进程中持有文件锁,在拉活进程启动后申请文件锁将会被阻塞,一旦成功获取到锁说明主进程挂掉了。如何在 Native 进程中拉活主进程:主要通过一个 am 命令即可拉活。说明:android5.0 后系统对 Native 进程加强了管理,利用 Native 进程拉活的方式已失效。
评论