1 java引用类型
4种引用类型:强引用(StrongReference),软引用(SoftReference),弱引用(WeakReference),幽灵引用(PhantomReference)。
强引用是最普遍的引用,如果一个对象具有强引用,那垃圾回收器绝不会回收它。
软引用强度上弱于强引用,它的作用是告诉回收器哪些对象是不那么重要,在内存不足时可以暂时回收。当JVM内存不足时,垃圾回收器会释放那些只被软引用所指向的对象。如果全部释放完这些对象之后,内存还不足,才会抛出OutOfMemory错误。软引用非常适合于创建缓存。当系统内存不足的时候,缓存中的内容是可以被释放的。通过类SoftReference来表示。
弱引用在强度上弱于软引用,通过类WeakReference来表示。它的作用是引用一个对象,但是并不阻止该对象被回收。如果使用一个强引用的话,只要该引用存在,那么被引用的对象是不能被回收的。弱引用则没有这个问题。在垃圾回收器运行的时候,如果一个对象的所有引用都是弱引用的话,该对象会被回收。弱引用的作用在于解决强引用所带来的对象之间在存活时间上的耦合关系。弱引用最常见的用处是在集合类中,尤其在哈希表中。哈希表的接口允许使用任何Java对象作为键来使用。当一个键值对被放入到哈希表中之后,哈希表对象本身就有了对这些键和值对象的引用。如果这种引用是强引用的话,那么只要哈希表对象本身还存活,其中所包含的键和值对象是不会被回收的。如果某个存活时间很长的哈希表中包含的键值对很多,最终就有可能消耗掉JVM中全部的内存。
幽灵引用,要先介绍Java提供的对象终止化机制(finalization)。在Object类里面有个finalize方法,其设计的初衷是在一个对象被真正回收之前,可以用来执行一些清理的工作。因为Java并没有提供类似C++的析构函数一样的机制,就通过 finalize方法来实现。但是问题在于垃圾回收器的运行时间是不固定的,所以这些清理工作的实际运行时间也是不能预知的。幽灵引用(phantom reference)可以解决这个问题。在创建幽灵引用PhantomReference的时候必须要指定一个引用队列。当一个对象的finalize方法已经被调用了之后,这个对象的幽灵引用会被加入到队列中。通过检查该队列里面的内容就知道一个对象是不是已经准备要被回收了。
幽灵引用及其队列的使用情况并不多见,主要用来实现比较精细的内存使用控制,这对于移动设备来说是很有意义的。程序可以在确定一个对象要被回收之后,再申请内存创建新的对象。通过这种方式可以使得程序所消耗的内存维持在一个相对较低的数量。
2 Android多进程
1 AIDL
AIDL 即AndroidInterface Definition Language的缩写,是专为 Android 中跨进程通信接口的描述语言。优缺点很明显,优点是稳定,快,Android 专门用于跨进程通信设计的。缺点是比较麻烦,AIDL 是通信的约定,参加通信的双方都需要把这个 AIDL 文件都加入自己的代码中,然后创建 Service 来实现访问和被访问。
2 ContentProvider
作为 Android 四大基础组件之一的 ContentProvider 本来它的作用只是提供内容性质的跨进程访问。但是在 API 11 (Android 3.0) 中,ContentProvider 加入了一个新的方法,可以用来进行跨进程的方法调用,ContentProvider 中这个方法的定义如下:
Bundle call(String method, String arg, Bundle extras)
从易用性来讲,这个没有 AIDL 那么麻烦,而且扩展性更强,也没有 Broadcast 过于依赖系统,API 11 应该就是主要是缺点了,别的缺点暂时没发现,欢迎补充。
3 Broadcast
广播是最简单的:优点是把分发消息的任务全部交给 Android 系统了;缺点也是因为全交给系统了,很多地方不受控制。缺点:
虽然广播可以通过指定包名来进行发送指向性消息,但是却不能验证消息去向 App 的签名。
系统重启之后,在系统的广播队列里边的消息就丢失了。
3 Java多线程之间的通讯
线程间的相互作用:线程之间需要一些协调通信,来共同完成一件任务。
wait()方法
wait()方法使得当前线程必须要等待,等到另外一个线程调用notify()或者notifyAll()方法。
线程调用wait()方法,释放它对锁的拥有权,然后等待另外的线程来通知它(通知的方式是notify()或者notifyAll()方法),这样它才能重新获得锁的拥有权和恢复执行。
要确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或synchronized块中。
notify()方法
notify()方法会唤醒一个等待当前对象的锁的线程。
如果多个线程在等待,它们中的一个将会选择被唤醒。这种选择是随意的,和具体实现有关。(线程等待一个对象的锁是由于调用了wait方法中的一个)。
被唤醒的线程是不能被执行的,需要等到当前线程放弃这个对象的锁。
被唤醒的线程将和其他线程以通常的方式进行竞争,来获得对象的锁。也就是说,被唤醒的线程并没有什么优先权,也没有什么劣势,对象的下一个线程还是需要通过一般性的竞争。
notify()方法应该是被拥有对象的锁的线程所调用。
(This method should only be called by a thread that is the owner of this object's monitor.)
换句话说,和wait()方法一样,notify方法调用必须放在synchronized方法或synchronized块中。
4 Android布局优化
Overdraw就是过度绘制,
Android提供了测量Overdraw的选项,在开发者选项-调试GPU过度绘制(Show GPU Overdraw),打开选项就可以看到当前页面Overdraw的状态.
第一招:合理选择控件容器。
LinearLayout易用,效率高,表达能力有限。RelativeLayout复杂,表达能力强,效率稍逊。
第二招:去掉window的默认背景
第三招:去掉其他不必要的背景
第四招:ClipRect & QuickReject
第五招:ViewStub
第六招:Merge
第七招:善用draw9patch
第八招:慎用Alpha
第九招:避免“OverDesign”
5 NestedScrollView 与CoordinatorLayout 机制
NestedScrollingParent
NestedScrollingChild
这是两个接口, Android 就是通过这两个接口, 来实现 子View 与父View 之间的嵌套滑动。