[lottery] 03_程序优化

Android 4.0

程序优化

一、对象的引用级别:
①强引用:对象创建,默认是强引用,宁愿抛出OOM异常,GC也不会清理强引用。如Object obj = new Object();
②软引用:SoftwareReference,在发生OOM异常之前,GC将清理所有的软引用
③弱引用: WeakReference ,GC在清理时,发现有弱引用,就会将其清理掉
④虚引用: PhantomReference,一创建,就会被清理掉
软引用:java.lang.ref.SoftReference<T>
软可到达对象的所有软引用都要保证在虚拟机抛出 OutOfMemoryError 之前已经被清除。

应用场景:
①申请内存速度不是过快(如ListView中item访问网络来获取图片展示)
②GridView 10张图片,但如果快速的滚动界面,那么GC来不及回收,会出现OOM异常
问题:
在UIManager中,维护着一个Map,该Map保存着所有的界面,
如果只有几个界面,还可以顶住,一般一个界面占用150K左右的内存,如果当存了100个Map后,那么内存将占用10M多,此时就无法在低内存下运行程序了,会出现OOM异常。
private Map<String, BaseView> views = new HashMap<String, BaseView>();
解决:这时就不能用强引用了,因为强引用在GC回收内存时,就算出现OOM异常,也不会回收强引用
那么用软引用SoftwareReference来
代码:
private static Map<String, BaseView> views;
    static {
        if (isHighMem()) {// 内存充足可用,直接用强引用
            views = new HashMap<String, BaseView>();
        } else {// 内存紧缺
            views = new MyReferenceMap<String, BaseView>();
        }
    }

package cn.zengfansheng.lottery.view.manager;
import java.lang.ref.SoftReference;
import java.util.HashMap;
/**
 * 软引用的集合
 * 
 * @param <K>
 * @param <V>
 */
public class MyReferenceMap<K, V> extends HashMap<K, V> {
    private static final long serialVersionUID = 1L;
    // note********************* *********************
    // 内存不足:GC会回收内存(对象的应用级别:1.2-------强引用、软引用、弱引用、虚引用),强引用对象宁愿抛出OOM异常,也不会清理
    // 降低引用级别
    
    private HashMap<K, SoftReference<V>> hashMapSR;
    // 将V给软引用
    
    public MyReferenceMap() {
        // Object obj = new Object();// 强引用(相当于手拿着一个手机)
        // 降低引用级别(将其装入一个袋子中)
        // SoftReference<Object> sr = new SoftReference<Object>(obj);// 本身是一个强引用
        // 相当于一个袋子,将obj(手机)装入袋子中去
        hashMapSR = new HashMap<K, SoftReference<V>>();
    }
    // put到集合中去(1、首先将其用一个软引用对象给引用起来 2、加入到集合中去)
    @Override
    public V put(K key, V value) {
        // 将传递进来的V,用一个软引用给引用起来
        SoftReference<V> sr = new SoftReference<V>(value);// 降低引用级别到软引用
        hashMapSR.put(key, sr);
        value = null;
        // 现在value是一个软可达到的对象
        return value;
    }
    // 从集合中get出来(1、首先将key到map中去取,2、取出的是软引用对象,3、再从该软引用对象中取出,如果为null说明被回收了)
    @Override
    public V get(Object key) {
        SoftReference<V> sr = hashMapSR.get(key);// 获取到“袋子”
        V v = sr.get();// 如果没有被清理掉,那么返回该key的引用;否则被清理了,返回null
        return v;
    }
    @Override
    public boolean containsKey(Object key) {
        SoftReference<V> sr = hashMapSR.get(key);// 获取到“袋子”
        return sr.get() == null;// 如果被GC回收掉false
    }
    // 还需要出什么方法?
    // map中需要使用什么方法,那么就在这里将其复写掉
}
核心代码:
package cn.zengfansheng.lottery.view.manager;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
/**
 * 软引用的集合
 * 
 * @param <K>
 * @param <V>
 */
public class MyReferenceMap<K, V> extends HashMap<K, V> {
    private static final long serialVersionUID = 1L;
    // note*********************1、软引用*********************
    // 内存不足:GC会回收内存(对象的应用级别:1.2-------强引用、软引用、弱引用、虚引用),强引用对象宁愿抛出OOM异常,也不会清理
    // 降低引用级别
    
    private HashMap<K, SoftReference<V>> hashMapSR;
    private ReferenceQueue<V> q;// 放置被回收掉手机的“袋子”的引用
    // 将V给软引用
    
    public MyReferenceMap() {
        // Object obj = new Object();// 强引用(相当于手拿着一个手机)
        // 降低引用级别(将其装入一个袋子中)
        // SoftReference<Object> sr = new SoftReference<Object>(obj);// 本身是一个强引用
        // 相当于一个袋子,将obj(手机)装入袋子中去
        hashMapSR = new HashMap<K, SoftReference<V>>();
        q = new ReferenceQueue<V>();// q一个队列,它会将每一个引用的对象,保存一个引用在里面
    }
    // put到集合中去(1、首先将其用一个软引用对象给引用起来 2、加入到集合中去)
    @Override
    public V put(K key, V value) {
        // SoftReference<V> sr = new SoftReference<V>(value, q);// 降低引用级别到软引用
        MySoftwareReference<K, V> sr = new MySoftwareReference<K, V>(key, value, q);
        hashMapSR.put(key, sr);
        value = null;
        // 现在value是一个软可达到的对象
        return value;
    }
    // 从集合中get出来(1、首先将key到map中去取,2、取出的是软引用对象,3、再从该软引用对象中取出,如果为null说明被回收了)
    @Override
    public V get(Object key) {
        SoftReference<V> sr = hashMapSR.get(key);// 获取到“袋子”
        V v = sr.get();// 如果没有被清理掉,那么返回该key的引用;否则被清理了,返回null
        return v;
    }
    @Override
    public boolean containsKey(Object key) {
        clearSRValue();
        SoftReference<V> sr = hashMapSR.get(key);// 获取到“袋子”
        if (sr != null) {// 说明软引用中有值,也就是有引用
            return true;
            // return sr.get() == null;// 如果被GC回收掉false
        } else {// 为null,说明没有引用了
            return false;
        }
    }
    // 还需要出什么方法?
    // map中需要使用什么方法,那么就在这里将其复写掉
    // note*********************2、软引用对象集合在被清空时,将其移除掉*********************
    // 当袋子内的手机已经被回收掉,清理掉强引用的袋子
    /**
     * 清理没有用的袋子
     */
    public void clearSRValue(){
        MySoftwareReference<K, V> sr = (MySoftwareReference<K, V>) q.poll();
        while (sr != null) {
            // /hashMapSR.remove(key);//由于要将其从map清除,所以需要一个key,但系统的Reference没有key,所以我们需要自定义,来增强
            // 从hashMapSR将sr清除
            hashMapSR.remove(sr.key);
            sr = (MySoftwareReference<K, V>) q.poll();
        }
    }
    /**
     * 自定义的SoftwareReference,增加一个key,用来在乱引用对象被GC回收时,将该软引用也给移除掉
     * 
     * @author hacket
     * 
     * @param <K>
     * @param <V>
     */
    private class MySoftwareReference<KVextends SoftReference<V> {
        Object key = null;
        public MySoftwareReference(K key, V value, ReferenceQueue<? super V> q) {
            super(value, q);
            this.key = key;
        }
    }
}