1.Application
- Application在一个Dalvik虚拟机里面只会存在一个实例,所以不需要弄单例模式去静态获取Application。
强调一个Dalvik虚拟机因为一个App有可能有多个Dalvik虚拟机就有多个不同的Application实例(Application的onCreate()方法也会执行多次Android中Application的onCreate多次调用问题),也就是传说中的多进程模式。多进程模式通过AIDL进行通信。
- Application的实质是一个Context它继承ContextWrapper。同样Application也有两个子类MultiDexApplication(如果遇到方法超过64K问题可以继承它完成分包工作)和MockApplication
由于在Context中可以通过getApplicationContext()获取到Application对象,或者是通过Activity.getApplication()、Service.getApplication()获取到Application(都是同一个对象),所以可以在Application保存全局的数据,供所有的Activity或者是Service使用。但是这里存在着一个坑,那就是在低内存情况下,Application有可能被销毁,从而导致保存在Application里面的数据信息丢失,最后程序错乱,甚至是Crash。所以当你想在Application保存数据的时候,请做好为空判断,或者是选择其他方式保存你的数据信息。不要在Android的Application对象中缓存数据!
最后,就是要注意Application的生命周期,他和Dalvik虚拟机生命周期一样长,所以在进行单例或者是静态变量的初始化操作时,一定要用Application作为Context进行初始化,否则会造成内存泄露的发生(若用Activity的实例,会造成该 Activity 在被销毁时将无法被回收)。使用Dialog的时候一般使用Activity作为Context,但是也可以使用Application作为上下文,前提是你必须设置Window类型为TYPE_SYSTEM_DIALOG,并且申请相关权限。这个时候弹出的Dialog是属于整个Application的,弹出这个Dialog的Activity销毁时也不会回收Dialog,只有在Application销毁时,这个Dialog才会自动消失。
2.内存泄漏
内存泄漏:是指程序由于错误或漏洞造成的内存占用过多,或占用内存后无法释放
内存溢出:是指已有的数据超过了其获得到的内存所能存储的范围,比如用一个字节存放1000这个数字就属于内存溢出
(1)Activity中内存泄漏的情况
一般是因为Activity的引用不能及时释放造成Activity销毁时不能被GC回收。
- Activity中非静态内部类(包括新开的子线程和匿名类(如AsycTask)因为每一个线程都被初始化为匿名内部类)在 Activity 的配置改变时(configChanges),由于每个非静态内部类都持有一个其外部类的隐式引用,使得Activity执行onDestroy()后 不会被 Java 的垃圾回收机制回收,而Activity又持有其 View 层以及相关联的所有资源文件的引用,后果会很严重
解决办法:使用静态内部类不会持有一个外部 Activity 的隐式引用,而且该 Activity 也会在配置改变后被回收,如果是线程的话则在onDestroy()方法中关闭线程。如果是AsycTask的话可以用静态内部类,由于静态内部类不持有Activity的引用所以可以将Activity实例弱引用(可见参考2)。
- Activity被静态变量引用(静态变量会常驻内存)
解决办法:最简单的方法是在onDestory方法中将静态变量activity置空,这样垃圾回收器就可以将静态变量回收。
- Activity中静态View(View一旦被加载到界面中将会持有一个Context对象的引用)
解决办法:最简单的方法是在onDestory方法中将静态变量View置空,这样垃圾回收器就可以将静态变量回收。
- 单例模式引用Activity的引用
解决办法:context=context.getApplicationContext();
- 用非静态匿名内部类的方式创建Handler引起的内存泄漏(由于mHandler是Handler的非静态匿名内部类的实例,所以它持有外部类Activity的引用,我们知道消息队列是在一个Looper线程中不断轮询处理消息,那么当这个Activity退出时消息队列中还有未处理的消息或者正在处理消息,而消息队列中的Message持有mHandler实例的引用,mHandler又持有Activity的引用,所以导致该Activity的内存资源无法及时回收,引发内存泄漏)
解决办法:创建一个静态Handler内部类,然后对Handler持有的对象使用弱引用,这样在回收时也可以回收Handler持有的对象,这样虽然避免了Activity泄漏,不过Looper线程的消息队列中还是可能会有待处理的消息,所以我们在Activity的Destroy时或者Stop时应该移除消息队列中的消息
- 资源未关闭造成的内存泄漏(对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。)
总结:详见参考2