Android高级进阶指南

原文地址 www.jianshu.com

1. android 触摸事件传递机制

 时间传递的三个阶段: 
  分发(dispatch) ---->  拦截(intercept) ---->消费(consume)
  在android 中拥有时间传递处理能力的类有以下三种
  Activity: 拥有dispatchTouchEvent  和  onTouchEvent两个方法
  ViewGroup:  拥有 dispatchTouchEvent , onInterceptTouchEvent, 和 onTouchEvent
  View: 拥有dispatchTouchEvent 和 onTouchEvent两个方法 

image

2. android view的绘制流程

android UI 管理系统层级关系
activity ->phoneWindow -> DecorView ->自己的布局
PhoneWindow 是android 系统中最基本的窗口系统, 每个activity 会创建一个, phoneWindow 是 activity 和 view系统交互的接口, decorView 本质上是一个FrameLayout , 是activity 中所有的view的祖先

绘制会从根视图ViewRoot 的 performTraversals()方法开始
视图绘制的过程分为三个步骤: 

测量(Measure):
Measure操作用来计算view的实际大小, 测量流程是从performMeasure方法开始的
重点关注三种测量模式: 
UNSPECIFIED: 不指定测量模式,父视图没有限制子视图的大小,子视图可以是想要的任何尺寸,通常用于系统内部,应用开发中很少使用
EXACTLY: 精确测量模式,当视图的layout_width 或者 layout_height制动具体的数值或者match_parent时生效,表示父视图已经决定了子视图的大小,这种模式下VIew的测量值就是SpecSIze的值
AT_MOST: 最大值模式,当该视图的layout_width或者layout_height指定wrap_parent时生效,此时子视图的尺寸是不超过父视图允许的最大尺寸的任何尺寸

布局(layout) :
layout 过程用来确定view在父容器中的布局位置,他是由父容器获取子view的位置参数后,调用子view的layout方法并讲位置参数传入实现的

绘制(draw):
draw操作用来将控件绘制出来,绘制的流程是从performDraw 方法开始的,最终会调用到每个View的draw方法绘制每个具体的view,绘制基本上可以分为六个步骤:
步骤一: 绘制view的背景
drawBackground(canvas)
步骤二: 如果需要的话,保存canvas的图层,为fading做准备
canvas.getSaveCount()
步骤三: 绘制view的内容
onDraw(canvas)
步骤四: 绘制view 的子view
dispatchDraw(canvas)
步骤五: 如果需要,绘制view的fading边缘并恢复图层
canvas.drawRect()
...
canvas.restoreToCount()
步骤六: 绘制view的装饰(例如滚动条)
onDrawScrollBars(canvas) 

3. android 的动画机制

android 3.0版本之前,可以使用逐帧动画和补间动画
3.0发布时,引入了属性动画
4.4的时候带来了android.transition框架

逐帧动画(Drawable Animation): 
他是利用人眼的视觉暂留效应-----也就是光对视网膜产生的视觉在光停止作用后,仍会保留一段时间现象
实现逐帧动画,就是由设计师给出一系列状态不断变化的图片,开发者可以指定动画中的每一帧对应的图片和持续时间,然后就可以开始播放动画了,有两种方式可以定义逐帧动画,分别是XML资源文件和代码实现

补间动画(Tween Animation)
补间动画是指开发者无须定义动画过程中的每一帧,只需定义动画的开发和结束这两个关键帧,并指定动画变化的时间和方式等,然后交给系统进行计算,通过两个关键帧之间插入渐变值来实现平滑过度,,从而实现动画效果,主要由四种效果可以动态组合,分别是:  
透明度变化Alpha
大小变化Scale
位移变化Translate
旋转变化Rotate
示例: 
从上向下无限循环移动
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="3000"
        android:fillAfter="false"
        android:fromYDelta="100"
        android:toYDelta="550"
        android:repeatCount="999999999"
        android:interpolator="@android:anim/linear_interpolator" />

</set>
//开始动画
scanAnim = AnimationUtils.loadAnimation(act,R.anim.scan_down)
iv_scan.startAnimation(scanAnim)
//停止动画
iv_scan.clearAnimation(scanAnim)

属性动画(Property Animation)
过度动画(Transition Animation) 

4. Support Annotation Library 库使用

注解库 

5. Percent Support Library 库使用

百分比控件库 

6. Design Support Library 库使用

比较新的控件库 

7. NDK 开发

ABI -> Application Binary Interface   应用程序二进制接口,android 平台指.so文件
目前android系统支持7种不同的CPU架构,每一种CPU架构对应一个ABI,对应android studio 中的目录文件如下:  
ARMv5->armeabi, ARMv7(从2010年起)->armeabi-v7a, x86(从2011年起)->x86 , MIPS(2012)->mips , ARMv8->arm64-v8a , MIPS6-> mips64, x86_64(2014年起)->x86-64 

8. Gradle 必知必会

共享变量----通用配置---aar函数库引用---签名和混淆配置

9. 通过Gradle 打包发布函数库到JCenter 和 Maven Central

10. Builder 模式详解

经典的Builder模式  
定义: 将一个复杂对象的构建和他的表示分离,使得同样的构建过程可以创建不同的表示
经典的Builder模式主要由四个参与者
1. Product:  被构造的复杂对象, ConcreteBuilder 用来创建该对象的内部表示,并定义他的装配过程
2. Builder: 抽象接口,用来定义创建Product 对象的各个组成部件的操作
3. ConcreteBuilder: Builder接口的具体实现,可以定义多个,是实际构建Product对象的地方,同时会提供一个返回Product的接口
4. Director: Builder 接口的构造者和使用者
示例如下: 
/* 定义:  将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建出不同的表示
 **/
public class Product {
    private String partOne;
    private String partTwo;

    public String getPartOne() {
        return partOne;
    }

    public void setPartOne(String partOne) {
        this.partOne = partOne;
    }

    public String getPartTwo() {
        return partTwo;
    }

    public void setPartTwo(String partTwo) {
        this.partTwo = partTwo;
    }
}

interface Builder {
    public void buildPartOne();

    public void buildPartTwo();

    public Product getProduct();

}

public class AConcreteBuilder implements Builder {
    private String TAG = "AConcreteBuilder";
    private Product product;

    @Override
    public void buildPartOne() {
        System.out.println(TAG+ "buildPartOne: ");
        product = new Product();
        product.setPartOne("AConcreteBuilder--buildPartOne");
        product.setPartTwo("AConcreteBuilder--buildPartTwo");
    }

    @Override
    public void buildPartTwo() {
        System.out.println(TAG+ "buildPartTwo: ");
//        product = new Product();
//        product.setPartTwo("AConcreteBuilder--buildPartTwo");
    }

    @Override
    public Product getProduct() {
        return product;
    }
}

public class BConcreteBuilder implements Builder {
    private Product product;
    private String TAG = "BConcreteBuilder";

    @Override
    public void buildPartOne() {
       System.out.println(TAG+"buildPartOne: ");
        product = new Product();
        product.setPartOne("BConcreteBuilder--buildPartOne");
    }

    @Override
    public void buildPartTwo() {
        System.out.println(TAG+"buildPartTwo: ");
        product = new Product();
        product.setPartOne("BConcreteBuilder--buildPartTwo");
    }

    @Override
    public Product getProduct() {
        return product;
    }
}

public class Director {
    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public void builderProduct(){
        builder.buildPartOne();
        builder.buildPartTwo();
    }

    public Product getProduct(){
        return builder.getProduct();
    }
}

    @Test
    public void builderTest(){
        System.out.println("123");
        Director director = new Director(new AConcreteBuilder());
        director.builderProduct();
        Product product = director.getProduct();
        System.out.println(product.getPartOne());
        System.out.println(product.getPartTwo());
    } 

变种Builder模式
可网上找个变种例子,一些开源库使用的就是变种builder模式,比如AlertDialog,Okhttp

11. 注解

1.编译时注解
2.运行时注解
3.元注解
定义注解
注册注解处理器
android的apt的注解插件 

12. ANR产生原因及定位分析

可通过 /data/anr/traces.txt 目录文件分析ANR
ANR的监测工具BlockCanary函数库,StructMode
内存监测工具LoakCanary
ANR发生的原因: 
1. activity 页面响应超过5s
2.broadcastReceiver 响应超过10s
3.service 响应超过20s

典型的ANR场景
1.UI线程存在耗时操作
2.UI线程等待子线程释放某个锁,无法处理用户的输入
3.动画的绘制需要大量的计算,导致CPU负载过重 

13. android 异步处理技术

Thread: 线程
在应用层主要分3类线程
1.UI线程,也是主线程
2.后台线程(也是子线程)
3.binder线程(进程之间的通信)
衍生顺序: 
Thread->HandleThread  ->intentServer(服务线程)
                                        ->AsyncQueryHandler(在contentProvider中使用)
            ->Executor Framework -> AsyncTask ->loader
HandleThread 是一个集成了looper 和 MessageQueue的线程 

14. android 数据序列化方案研究

1.java中使用的Serializable ,主要应用于磁盘和网络中
原理: 使用java中的反射机制,在序列化过程中会创建多个临时对象,很容易就触发系统的回收机制,性能比较低, 也是对象转换成字节的过程,反序列化就是字节转化成对象的过程.
序列化过程:  先创建某种类型的OutputStream(如 FileOutputSteam),接着将这些Outputstream封装到一个ObjectOutputstream中,然后可以调用ObjectOutputStream 的writeobject方法,写完之后记得关闭各项
2.android 的 parcelable 序列化,android sdk 提供,操作的对象是内存,速度较serialiable快很多,kotlin中可直接使用注解序列化
3.SQLDataBase ,sqllite数据库
4.sharepreference 数据存储
5.json
6.FlatBuffers 是google提供的序列化函数库,注重性能和资源的使用 

15. android Webview java 和 JS 交互

java调用js直接loadUrl
js调用java通过webSetting类的诸多方法 

16. MVP,MVVM,MVC模式 +MVI模式

MVC
view层,control层,model层,关系是个三角关系

MVP  
是MVC模式的延伸和改进,view层-><-presenter层-><-model层
优势: 
1.如果界面发生改变,只需要改变view层
2.如果业务逻辑或者数据获取方式改变,只需要修改model层
3.如果控制逻辑发生改变,只需要改变persenter层
4.业务的交互都是通过接口实现的,有利于新成员接触代码,也可根据事先定义好接口,功能交给不同的人开发
劣势
1.接口过多,代码量,方法数增加
2.由于进行了三层划分,函数的调用栈变浅了,这对开发人员的对代码的认识就变高了,如果开发人员没能分清楚那一层具体该负责哪些功能,那么就会造成代码的乱入,mvp也就达不到充分解耦的目的.

MVVM
是MVP模式的延伸和改进:  view层->viewModel层-><-model层
关键点在viewmodel,还引入了databinding的概念--以UI驱动数据

MVI
优势
*   对于架构来说,维护状态不再是那么困难的事情了。它主要做的就是状态维护;
*   因为数据流是单向的,所以可以很容易的被跟踪和预测;
*   它确保线程是安全的,因为状态对象是不可变的;
*   容易进行Debug,当错误发生时,我们可以知道对象的状态;
*   更加的解耦,每个组件专注自己的业务和逻辑;
*   app的测试将会很容易,我们可以将不同的业务逻辑映射为状态。
劣势
*   每一个用户的动作来维护一个状态,可能会导致大量的模版代码。
*   对于所有的状态,必须创建大量的对象;这样对app的管理会成本比较高。
*   处理一个警告的状态可能会比较困难,因为我们可能会更改配置。举个例子,如果没有网络,我们要在`snackBar`上显示,对于配置的更改,`snackBar`将会重新显示。就可用性而言,这里必须处理。 

17. Jetpack库的使用

Databinding:UI驱动数据  Paging3 DataStore WorkManager Room 等 

18. 观察者模式扩展,事件总线

观察者模式概念: 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于他的对象都得到通知并自动更新
原理
几个事件分别是:
1.事件 Event
2.订阅者 Subscrber
3.发布者 Publisher
4.总线 EventBus
publisher ---post Event--->EventBus ---event--->Subscriber1号
                                                           ---event--->Subscriber2号
开源实现库 EventBus 

19. 书写简单规范代码

1.严格遵守java编码规范
2.Android的一些命名规范
3.可以使用checkstyle 对项目的规范就行检测 

20. 搭建自己的技术堆栈

APP整体架构
较高的层次来讲,一个app的整体架构可以分为两层,应用层和基础框架层
1.应用层专注于行业领域的实现,例如金融,支付,地图导航,社交,他直接面向用户,是用户对产品的第一层感知
2.基础框架层专注于技术领域的实现,提供app公有的特性,避免重复制造轮子,他是用户对产品的第二层感知,例如性能,稳定性等
一个理想的App架构,首先应该是支持跨平台开发的,其次应该具有清晰的层次划分,同一层之间模块充分解耦,模块内部符合面向对象设计六大原则,最后应该在功能,性能,稳定性等方面达到综合最优. 

image

21. 64K方法数限制原理和解决方案

APK本质上是一个压缩包,里面包含classes.dex是一个可执行Dalvik字节码文件,这个.dex文件存放的事所有编译后的java代码,dalvik可执行文件规范单个.dex文件最多能引用的方法数是65536个,这其中包含android framework,app引用的第三方函数库以及app自身的方法
解决方案
使用MultiDex解决.俗称分包,就是将一个dex装不下的方法分成多个dex装
其实MultiDex是一个不得已而为之的方案,它本身并不是完美的,他会导致编译非常的慢
在开发阶段优化MultiDex的构建
之所以MultiDex构建如此缓慢,是因为构建系统需要经过复杂的计算决定哪些类要包含在主dex文件中,哪些类可以包含在从dex中.为了解决这个问题,减少开发阶段的构建时间,我们可以在工程的主模块的build.gradle文件中使用productFlavors来创建两个flavor,一个是开发阶段使用的,一个是生产阶段使用的,开发阶段的flavor 中,设置minSDKVersion 为21,这使得构建系统使用ART支持的格式更快的生成MultiDex的输出,生产阶段的flavor中,设置minSdkVersion为应用时机支持的最低版本号 

22. android 插件框架机制研究

为了解决APK随着开发周期的延长,需求的增多,APK的运行会越来越缓慢,这时插件化框架应运而生,虽然google提出了MultiDex的方案,但我们都知道他并不是很完美.插件化框架的基本形式是将一个APK中的不同功能模块进行拆分,并大儒道不同的dex文件或者apk文件中,主工程只是一个空壳,提供了用来加载模块dex或者apk的框架,使用插件框架的好处也有很多: 
1.提升AS工程的构建速度
2.提高应用的启动速度
3.支持多团队开发
4.在线动态加载或者更新模块
5.按需加载不同的模块,实现灵活的功能配置

ClassLoader机制
android中的Classloader机制是用来加载dex文件,系统提供了两个API可供选择
1.PathClassLoader: 只能加载已经安装到android系统的apk文件
2.DexClassLoader: 支持加载外部的apk,jar,或者dex文件,,正好符合插件化的需求,所以有的插件化方案都是使用的DexClassLoader 来加载插件的APK中的.class文件的

开源的插件框架
1.Shadow https://github.com/Tencent/Shadow
2.Replugin https://github.com/Qihoo360/RePlugin
3.Qigsaw  https://github.com/iqiyi/Qigsaw/blob/master/README.zh-CN.md
4.Small 

23. 推送机制实现原理详解

开源实现
1.基于XMPP协议
2.基于MQTT协议

第三方平台
百度,小米,极光,友盟等

自己实现推送功能
通过网络套接字socket,他封装了很多tcp的操作,对移动端来说,一个推送的基本框架需要包括: 
1.和服务端建立连接的功能
2.发送数据给服务端的功能
3.从服务端接收推送数据的功能
4.心跳包的实现 

24. APP瘦身经验

1.优化图片资源占用的空间
2.使用Lint工具删除无用的资源
3.利用gradle的配置,减少最后生成的apk包大小
4.重构和优化代码
5.资源混淆
6.插件化 

25. android Carsh 日志收集原理与实践

定义
java中常用的异常主要有两类,一种是编译时的异常(CheckedException),必须在编译时期进行处理,常用操作就是使用try..catch捕获进行处理.另外一种是运行时异常(UnCheckedException),这类异常在编译时期是检测不出来的,只有在运行阶段特定的情况下触发才能检测出来.

原理
java API提供的全局的异常捕获处理器 Thread.UncaughtExceptionHandler 处理器,通常情况下我们只需要实现这个接口,重写他的uncaughtException放,在该方法就可以读取carsh的堆栈信息,注意一点要在app启动的时候注册哦,不然他还是沿用的系统默认的异常处理 

26. 函数式编程思想

RxJava,RxAndroid,Agera,这几个函数式框架,都提现了Android的函数式编程 

27. 依赖注入在android的使用

优势
依赖注入让开发者可以编写低耦合的代码,他解耦了依赖者和被依赖者,代码易于单元测试

依赖注入(简称 DI )也可以称为控制反转(Inversion of Control) 简称IoC,IoC一般分为两种类型,一种就是依赖注入,另一种就是依赖查找

复杂的项目建议直接使用依赖注入框架,常用的依赖注入框架有
1.BufferKnife
2.RoboGuice
3.Dagger -> Hilt
4.koin

28. kotlin 在android中的使用

flow 委托 与java相互调用 协程......

29. 混合开发

flutter模块化 ReactNative模块化 flutter插件 uniapp插件  小程序集成(Taro一个开放式跨端跨框架解决方案)

30. 在线热修复方案

原理
线上的正式包APK称为宿主APK,补丁包称为补丁APK,线上出现问题后,需在线下载补丁APK,使用补丁APK中的函数替换原来的函数,从而实现修复bug的功能

热修复框架
1.tinker  腾讯复杂集成 免费
2.sophix 阿里简单集成 收费 

31. 面向切面编程

AOP (Aspect Oriented Programming) 即面向切面编程
可以使用AspectJ进行 android 平台的切面编程
1.Hugo 插件 

32. FaceBook Buck 改造android 构建系统

33. 代码优化,图片优化,网络优化,电量优化,布局优化

34. android 混淆机制详解

混淆的目的是为了保护自己的知识产权,增加别人的反编译难度
Android的混淆包括三种类型: 
1.java代码混淆
2.Native (C 和 C++) 代码混淆
3.资源文件的混淆

主要混淆还是在java代码层,java代码层的混淆一般依赖于proguard 或者 dexguard 工具,
proguard是免费开源的,但功能有限,dexguard是收费的
proguard 特性
1.压缩,优化,混淆,预检验
Android Studio 创建项目的时候默认是使用Proguard 的,其中proguard-Android.text 是Proguard 默认的混淆配置文件,位于 Android SDK 的 tools/proguard目录中 ,项目根目录下的 proguard-rules.pro文件也是编写混淆的文件 

35.android逆向 反编译机制

Smali语言 so库 借助第三方的反编译工具 APKTool 等

36. 客户敏感信息隐藏技术研究

37. android 加固技术研究

加固的目的和混淆的目的其实是一致的,都是为了保护自己的知识产权,防止反编译,一些常用的第三方加固有:  
1.梆梆加固
2.爱加固
3.迦娜
4.360加固
5.腾讯加固
6.百度加固等 

38. android 安全编码

一些保证编写代码安全的建议,如
1.WebVIew 远程代码执行
2.WebView 密码明文保存
3.Android 本地拒绝服务
4.SharedPreference 全局任意读写
5.密码硬编码
6.弱加密
7.PendingIntent 使用不当 等 

39. android 调试工具 Facebook Stetho

40. 内存泄漏检测函数库 LeakCanary

LeakCanary 检测内存泄漏的原理
RefWatcher.watch() 函数会为被监控的对象创建一个 KeyedWeakReference 弱引用对象, KeyedWeakReference  是 WeakReference 的子类,增加了键值对信息,后面会根据指定的键值key 找到弱引用对象
在后台线程AndroidWatchExecutor 中,检查 KeyedWeakReference 弱引用是否已经被清除,如果还存在,则触发一次 垃圾回收机制,垃圾回收之后,如果弱引用对象依然存在,说明发生了内存泄漏 

41. 基于Facebook Redex 实现 APK的压缩和优化

42. android studio 你所需要知道功能

1.Annotate  git记录代码作者编写工具
2..ignore 插件 

43. android 单元测试框架简介

44. android UI自动化测试框架简介

45. android 静态代码分析

46. Jenkins+Gradle 搭建android 持续集成编译环境

posted @ 2023-04-21 14:02  cps666  阅读(48)  评论(0编辑  收藏  举报