[view] 12_3DGallery内存优化-可以装载大量图片

Android 4.0

3DGallery内存优化-可以装载大量图片

问题:如果加载的图片过多,会导致OOM溢出
分析:这是由于一次性大量将图片加载到内存,会导致内部不足,Out Of Memory异常。
解决:可以通过软引用、弱引用来解决
软引用:如果一个对象只具有软引用,那就类似于可有可物的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只 要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。 软引用可以和一个引用队列(ReferenceQueue)联 合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
弱引用:如果一个对象只具有弱引用,那就类似于可有可物的生活用品。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。  弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回 收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
解决后代码:
package cn.zengfansheng.customeGallery.adapter;
 
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
 
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Gallery.LayoutParams;
import android.widget.ImageView;
 
public class ImageAdapter extends BaseAdapter {
 
    private static final String TAG = "ImageAdapter";
 
    private Context context;
    private int[] imageIds;
 
    //private List<ImageView> imageViews;
 
    /**
     * 软引用
     */

    private Map<Integer, SoftReference<ImageView>> map;
 
    public ImageAdapter(Context context, int[] imageIds) {
        this.context = context;
        this.imageIds = imageIds;
 
        //imageViews = new ArrayList<ImageView>();
        map = new HashMap<Integer, SoftReference<ImageView>>();
        intiImageView();
    }
 
    /**
     * 初始化ImageView
     */

    public void intiImageView(){
        for (int i = 0; i < imageIds.length; i++) {
            // 通过id获取倒影合成的ImageView
            ImageView invertImageView = getInvertImage(imageIds[i]);
 
            // 用一个软引用关联该倒影ImageView
            SoftReference<ImageView> softReferenceIV = new SoftReference<ImageView>(invertImageView);
 
            // 将该软引用加到map中去
            map.put(i, softReferenceIV);
        }
    }
    /**
     * 生成倒影的图片,并合成
     */

    public ImageView getInvertImage(int imageId) {
 
        int interval = 5;//间隔,原始图片和倒影图片的间隔
 
        //1、获取原始bitmap
        Bitmap resourceBitmap = BitmapFactory.decodeResource(context.getResources(), imageId);
 
        // 原始bitmap的宽高
        int width = resourceBitmap.getWidth();
        int height = resourceBitmap.getHeight();
 
        //2、获取倒影bitmap
        Matrix matrix = new Matrix();
        float[] values = new float[]{
                1,0,0,
                0,-1,resourceBitmap.getHeight(),
                0,0,1
        };
        matrix.setValues(values);
        // matrix.setRotate(180, 1, -1);
        //倒影的bitmap
        Bitmap invertBitmap = Bitmap.createBitmap(resourceBitmap,0,height/2,width,height/2, matrix, false);
 
        //3、创建一个空的bitmap
        Config config = Config.ARGB_8888;// 4B表示一个像素
        Bitmap resultBitmap = Bitmap.createBitmap(width, (int) (height * 1.5 + 10), config);
 
        // 4、用画笔在这空白的bitmap上画
        Canvas canvas = new Canvas(resultBitmap);
 
        // 4-1画原始bitmap
        Paint defaultPaint = new Paint();
        canvas.drawBitmap(resourceBitmap, 0, 0, defaultPaint);
 
        // 画个矩形间隔
        canvas.drawRect(0, height, width, height + interval, defaultPaint);
 
        // 4-2画倒影的bimmap
        canvas.drawBitmap(invertBitmap, 0, height + interval, defaultPaint);
 
        // 5、设置给ImageView并抗锯齿
        BitmapDrawable bitmapDrawable = new BitmapDrawable(context.getResources(), resultBitmap);
        bitmapDrawable.setAntiAlias(true);// 抗锯齿,平滑效果
 
        ImageView iv = new ImageView(context);
        iv.setImageDrawable(bitmapDrawable);
 
        // 7、设置显示图片的大小
        @SuppressWarnings("deprecation")
        LayoutParams params = new LayoutParams(160, 320);
        iv.setLayoutParams(params);
 
        // 8、遮罩
        Paint paint = new Paint();
        paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));
 
        // 9、渐变
        Shader shader = new LinearGradient(0, height, 0, resultBitmap.getHeight(),0x70ffffff, 0x00ffffff, TileMode.CLAMP);
        paint.setShader(shader );
        canvas.drawRect(0, height, width, resultBitmap.getHeight(), paint);
 
        // 10、返回倒影的ImageView
        return iv;
    }
 
    @Override
    public int getCount() {
        /*if (imageViews != null) {
            return imageViews.size();// 擦,没有return
        }*/

        if (map!=null) {
            return map.size();
        }
        return 0;
    }
 
    @Override
    public Object getItem(int position) {
        return null;
    }
 
    @Override
    public long getItemId(int position) {
        return position;
    }
 
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
 
        // 从集合中获取指定位置的软引用
        SoftReference<ImageView> ivSoftReference = map.get(position);
 
        // 获取该软引用引用的对象
        ImageView imageView = ivSoftReference.get();//得到所引用的对象,如果为null,表示已经被垃圾回收器回收
        if (imageView == null) {// 如果为null,说明已经被回收,那么重新创建一个
            Log.i(TAG, "回收对象:"+position);
            imageView = getInvertImage(imageIds[position]);
        }
        // 否则,用该软引用所引用的对象
        return imageView;
 
        // return imageViews.get(position);
    }
}
结果:
可以看到,当到了15后,14,13直接从软引用中get()数据了,而不是重新创建对象