Android — 初始 JNI 和 NDK

前言

最近热修复和插件化炒得火热,是时候头铁开始尝试学习了。那么他们有什么用途吗?

在热修复出现之前,一个已经上线的 APP 如果出现了 Bug,即使是一个非常小的 Bug,不及时更新的话有可能存在风险,若要及时更新就得将 APP 重新打包发布到应用市场,让用户再一次下载,这就大大降低了用户体验,当热修复出现之后,这样的问题就不再是问题了。

对于插件化,如其名,一个程序划分为不同的部分,以插件的形式加载到应用中去,本质上它使用的技术还是热修复技术,只不过是加入了更多的工程实践,让它支持大规模的代码更新以及资源和 so 包的更新。

然而要想更加容易理解热修复和插件化,还是要先学好 JNI 和 NDK 知识的。但是我对 JNI 和 NDK 完全不知呀,不慌不慌,撸会猫,然后一起学习。

more >>


Java — 类的加载过程

前言

今天在看 DCL 单例模式实现的时候,看到了作者分析 DCL 可能失效的问题,实际上讨论的是类的加载过程。比如执行 SingleTon singleTon = new SingleTon() ,这里看起来是一句代码,但实际上并不是一个原子操作,这句代码最终会被编译成多条汇编指令,它大致做了三件事情:

  1. 给 SingleTon 的实例分配内存;
  2. 调用SingleTon 的构造函数,初始化成员字段;
  3. 将 singleTon 对象指向分配的内存空间;

实际上还是有点懵,既然都挑事了,那就说明白点,枪一些博文(逃

类的加载过程概论

类从被加载到虚拟机内存开始,知道卸载出内存,它的生命周期包含了:加载,验证,准备,解析,初始化,使用和卸载七个阶段。

  1. 加载

    将该类的 .class 文件中二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class 对象,用来封装类在方法区内的数据结构。在这个阶段,会执行类中声明的静态代码块。也就是说类中的静态块执行时是不需要等到类的初始化完成。

  2. 连接

    类加载完成后就进入了类的连接阶段,在连接阶段,主要是将已经读到内存的类的二进制数据合并到虚拟机的运行时环境中去。连接阶段也分为三个过程:

    • 验证

      验证是连接阶段的第一步,这一阶段的目的是为了确保 Class 文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

    • 准备

      准备阶段是正式为 类变量 分配内存并设置其初始值的时候,内存都是被分配到方法区中。准备阶段不会分配类中实例变量的内存,实例变量的内存将会在对象实例化的时候随着对象一起分配到 Java 内存中。例如:public static int value = 123 ;在准备阶段 value 的初始值为 0,在初始化阶段才会变为123。而对于 static final 类型的变量,在准备阶段就会被赋值为正确的值。

    • 解析

      解析阶段是将符号引用转化为直接引用的过程。

      符号引用是用一组符号来表示所引用的类和接口的全限定名、字段的名字和类型、方法的名字和类型,只要使用时可以无歧义的定位即可。符号引用与虚拟机实现的内存布局无关,引用的目标并不一定已经加载到内存中。

      直接引用是直接指向目标的指针、相对偏移量和一个能间接定位到目标的句柄。直接引用于虚拟机的内存布局是相关的,有了直接引用,说明引用的目标已经在内存中。

插播一下,为什么要将类、方法或者变量声明为 final 呢?

我们都知道,final 修饰的类不可继承,修饰的方法不可重写,修饰的变量不可重写赋值。但是说到优点,可能还真的说不上来。这就要提及的代码优化了,Java 编译器会寻找机会内联所有的 final 方法,内联对于提升 java 运行效率作用很大,平均能使性能提高 50%。

参见自:35 个 Java 代码性能优化总结

  1. 初始化

    在这个阶段主要执行类的构造方法,并且为静态变量赋值为初始值,执行静态代码块。

    如果你仔细读了上面的文章的话,你是不是发现了一个问题,前后不一致?静态代码块到底是在加载的时候被执行了还是在初始化时被执行了?实际是是在初始化的时候执行的。我看的这个博客是有点问题的。

    初始化阶段是执行类构造器< clinit >() 方法的过程。该方法是由编译器自动收集类中的类变量的赋值动作和静态语句块中的语句合并产生。

    虚拟机会保证类的初始化在多线程环境中被正确的加锁、同步,即如果多个线程同时去初始化一个类,那么只有一个类去执行这个类的< clinit > 方法,其他线程都要阻塞等待,直至活动线程执行完该方法。因此如果在一个类的 < clinit >() 方法中有耗时的操作,那就可能造成多个进程阻塞。不过其他线程虽然会阻塞,但是执行完 < clinit >() 方法的那个线程退出< clinit >() 后,其他线程就不会再次进入 < clinit >() 方法。因为在同一个类加载器下,一个类只会初始化一次。也就是说初始化之前的阶段可以有多个线程执行,而初始化阶段只能有一个线程执行。

    类需要初始化的情况有以下几种:

    • 创建类的实例
    • 访问某个类或接口的静态变量,或者对该静态变量赋值
    • 调用类的静态方法
    • 反射
    • 初始化一个类的子类
    • Java 虚拟机启动时被标明启动类的类

剩下的阶段就不用说了,最后附上参考链接,其中第一篇有些说法有误,第三篇博客是对该问题的详细阐述和证明。

参考:

http://www.jianshu.com/p/6c91e07c293f

http://www.jianshu.com/p/79e0e9487b69

http://blog.csdn.net/jiese1990/article/details/40154329

http://www.cnblogs.com/ivanfu/archive/2012/02/12/2347817.html


拒绝浮躁

前言

昨天还在说迷茫呢,今天就收到一个特别的推送,真的很感谢。迷茫的本质还是过于浮躁,所以有些事情想做但是又不想做。这句话可能有点难以理解吧。在迷茫的时候要保持头脑清晰,多看看别人的想法,虽然我很不喜欢鸡汤文,但是有时候鸡汤文能让你清醒。

如果成为一个技术牛人?请不要做一个浮躁的程序猿

  1. 不要放过任何一个看上去很简单的小问题 — 他们往往并不简单,或者可以引申出很多知识;不会举一反三你永远学不会。
  2. 知道一点东西,并不能说明你会写应用,完整的应用是需要经验积累的。
  3. 在任何时候都不要认为手中的书已经足够了。
  4. 看得懂的书,请仔细看;看不懂的书,请硬着头皮看。
  5. 别指望看第一遍书就能记住和掌握什么,请看第二遍第三遍。
  6. 当你编程到一半却发现自己用的方法很拙劣时,请不要马上停手;尽快将余下的部分粗略的完成以保证这个代码的完整性,然后分析自己的错误并重新编写和工作。
  7. 每学一个难点的时候,尝试着对别人讲解这个知识点并让他理解,你能讲清楚才说明你真的理解了。

最后

再次感谢 Java和Android架构 公众号。以上摘自:如何成为一个技术牛人?请不要做一个浮躁的程序员

最后,我觉得昨天可能是听歌听太多了,把脑袋都听得胀胀的。睡了一晚,起来头脑就很清醒了。

迷茫不可怕,怕在迷茫之后一直找不到路。

Flighting,当当猫!


谁的青春不迷茫

不知道为什么,这两天好迷茫,不知道该做什么。其实好像也算不上迷茫,知道要做什么但是不想做,心情烦躁。难道是因为最近一直下雨?也说不好。

想来想去,感觉有个办法估计可行,那就是上牛客网做做题。

emmmm,为了坚持每天 commit ,这次水了一下,QwQ


Android — Activity 异常情况下的生命周期

前言

看了任玉刚老师的 living 之后,只能说大牛就是大牛。怀着敬畏的态度研读他的著作 — 《Android 开发艺术探索》,毫不夸张的说这本书绝对算是 Android 进阶必读书了。本菜鸡看了第一章就收获颇丰,以下就是一些读书笔记,例子都是枪书上的,感谢任老师。

Activity 正常情况下的生命周期估计大家随口都能说出,那么在异常情况下的生命周期你知道吗?首先,哪些是异常情况呢?emmmm,有以下常见的两种情况:

  1. 资源相关的系统配置发生改变导致 Activity 被杀死并重新创建。
  2. 资源内存不足导致低优先级的 Activity 被杀死

对于情况一,乍一听可能有点懵,那就举一个实例 — 横竖屏的切换。我们知道,在这种情况下,Activity 是销毁后再重新创建的,当然,我们也可以阻止系统重新创建Activity 。但是,他不会是简单的销毁重建,为什么这么说呢?让我们页面上的视频时,看到一半我们切换到全屏,这时候它会保存我们的观看进度,那这是这么实现的呢?对于情况二,这个还真的不好模拟,那就只能理论分析咯。

more >>

我们一直都向往,面朝大海,春暖花开。 但是几人能做到,心中有爱,四季不败?