小木箱@Singapore
小木箱@Singapore
### 为什么Tinker热修复需要重启应用生效? - `dexopt/dexoat` 操作是非常耗时的, 在`Art` 虚拟机影响非常大,因为`loadDex` 是补丁 `dex` 和 `APK` 中原 `dex` 合并成的一个完整的补丁压缩包,所以`dexoat` 操作非常耗时.如果优化后 `odex` 文件没有生成,或者生成不完整,那么`loadDex` 边不能在应用启动的时候进行,因为会阻塞`loadDex`进程,一般是主线程,所谓为了解决这个问题,我们把`loadDex` 当做一个事务来处理,如果中途打断,那么删除`odex` 文件,`loadDex` 完之后,反射注入/替换 `dexElements` 数组,实现打包。如果不存在`odex` 文件,那么重启另外一个子线程`loadDex` ,重启之后再生效 - 补丁包安全性,对补丁包进行签名校验,这个时候防止补丁包被篡改,实际上虚拟机执行的是`odex`而不是`dex`,还需要进行`odex`文件进行校验进行`MD5` 完整性校验,如果匹配,则直接加载,如果不匹配,则重新生成`odex`文件,防止`odex`文件被篡改
- 尽可能持有application上下文,而不是activity上下文 - 使用资源(如: File,Currsour, Bitmap,音频,视频)即时关闭 - Runnable 做操作的时候,如果`Activity`和`Fragment`消失的时候,及时关闭线程 - onCreate 或 onStart 如果注册相关监听事件的时候,记得即时关闭 - 非静态内部类 或者 匿名内部类会持有外包类的引用导致内存泄漏,在不需要使用的时候,主动置空或者使用弱引用
开讲前,先思考以下几个问题:  1. 假如入我们要自己定制一个`Handler`,你会考虑怎么做?  2. 让你设计一个线程池,如果调用者在传入的`Runnable`任务时,在`run`方法直接使用了`Handler`,会发生什么?  3. `IntentService`里面也有一个`Handler`,它是如何结束执行呢,如果多次`start`这个`IntentService`,它又如何判断什么时候结束呢?  4. `Android` 子线程为什么不能访问`UI`? 一定不能访问`UI`吗?了解这些问题我们首先需要了解`Handler`的本质,`Handler`实质是在指定线程中运行代码.下面就开始我们的`Handler`源码之旅吧~ ### 一.ThreadLocal   `Handler` 的`ThreadLocal` 是给每一个线程都分配了内容,泛型里面分配了`Thread`对象.我们用`Integer`模拟一下`ThreadLocal`原理 运行以下`example`: ```java final ThreadLocal mThreadLocal = new ThreadLocal(); mThreadLocal.set(1); Log.e("ThreadLocalTest","thread0"+mThreadLocal+""); new Thread("thread1"){ @Override public void run() { mThreadLocal.set(2);...
## UDP | TCP #### 一.`UDP` 和`TCP` 区别    `TCP`是面向连接的,例如:直播的`RTMP`协议,会有丢包的风险,但是在直播行业里面,宁可丢包,也不要卡顿或者丢帧,`UDP` 也是面向连接的,如:很多直播行业,网络状况不佳,会遵循`UDP`协议来实现自己的网络协议,因为`TCP`协议会降低网络速度,视频播放会卡的不行。 #### 二.`TCP` 三次握手 - A: 您好 , 我是 A - B: 您好A , 我是 B - A: 您好B -...
这是来自QQ邮箱的假期自动回复邮件。 您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
这是来自QQ邮箱的假期自动回复邮件。 您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
[Handler的智慧,从终极问题出发](https://juejin.im/post/5b2715c2f265da5959468781)
数据结构很薄弱,需要恶补! java8不是用红黑树来管理hashmap,而是在hash值相同的情况下(且重复数量大于8),用红黑树来管理数据。 红黑树相当于排序数据,可以自动的使用二分法进行定位,性能较高。 红黑树他有如下特性: 1)每个结点要么是红的,要么是黑的。 2)根结点是黑的。 3)每个叶结点(叶结点即指树尾端NIL指针或NULL结点)是黑的。 4)如果一个结点是红的,那么它的俩个儿子都是黑的。 5)对于任一结点而言,其到叶结点树尾端NIL指针的每一条路径都包含相同数目的黑结点。 二叉树的时间 最终查找、插入、删除的时间复杂度最坏情况下都是O(logn)
1. 注入前加载的类(比如:Application 类) 肯定是不能被修复的 - 保底方案: 在没法应用部署或者热部署失败方案下,最后应用代码冷启动重启生效方案生效,所以我们的补丁是同一套 2. 热修复在初始化过程中,可以放到`attatchBaseContext` 进行初始化,但是,`attatchBaseContext`,有相当多的限制,比如:不能进行网络请求下载新补丁,因为`App`申请的权限还没有授予完成,然后有人会问了,我放`oncreate`不就行了,其实放`oncreate` 问题也有,如果你的清单文件里面有内容提供者,或者其他第三方`Application`里面有内容提供者,`ContentProvider`是优先`Application.onCreate`加载的,具体先后顺序如下: `Application.attatchBaseContext` -> `ContentProvider.onCreate` -> `Application.onCreate` -> `Activity.onCreate`,所以为了保险起见,还是将入口类放在`attatchBaseContext`比较好 3. `BuildConfig` 是编译期动态生成的,属于非系统类,获取版本信息会导致提前引入问题,所以建议使用`PackageManager` 来获取版本号。
### 基准取头法 固定基准元,一般选取中间值或头部值或尾部值。如果输入序列是随机的,处理时间是可以接受的。如果数组已经有序时或部分有序,此时的分割就是一个非常不好的分割。因为每次划分只能使待排序序列减一,数组全部有序时,此时为最坏情况,快速排序沦为冒泡排序,时间复杂度为O(n^2)。所以此种方式要慎用。  ### 基准取中法  三数取中,一般是分别取出数组的头部元素,尾部元素和中部元素, 在这三个数中取出中位数,作为基准元素。最佳的划分是将待排序的序列分成等长的子序列,最佳的状态我们可以使用序列的中间的值,也就是第N/2个数。可是,这很难算出来,并且会明显减慢快速排序的速度。这样的中值的估计可以通过随机选取三个元素并用它们的中值作为枢纽元而得到。事实上,随机性并没有多大的帮助,因此一般的做法是使用左端、右端和中心位置上的三个元素的中值作为枢纽元。显然使用三数中值分割法消除了预排序输入的不好情形。(简单来说,就是随机取三个数,取中位数)。