解决读取bitmap内存溢出问题

来源:互联网 发布:mysql 修改列字符集 编辑:程序博客网 时间:2024/06/05 03:48

官方文档解决办法:http://developer.android.com/training/displaying-bitmaps/index.html


一、有效的加载大图(Loading Large Bitmaps Efficiently)

1.读取图片的密度和类型(Read Bitmap Dimensions and Type)

BitmapFactory.Options options = new BitmapFactory.Options();

options.inJustDecodeBounds = true;  //设置为true调用BitmapFactory的decode方法不会分配内存,返回一个空的bitmap

BitmapFactory.decodeResource(getResources(), R.id.myimage, options);  //返回为null  ,不分配内存

int imageHeight = options.outHeight;   //图片的高度

int imageWidth = options.outWidth;    //图片的宽度

String imageType = options.outMimeType;  //图片的类型

根据图片的高度和宽度可以计算出图片的密度,是否大于系统要求的内存,防止内存溢出,然后设置options.inJustDecodeBounds = false;

否则用BitmapFactory生成的Bitmap返回值为null


2.加载缩小的图片到内存(Load a Scaled Down Version into Memory)

options.inSampleSize = 3;  通过BitmapFactory得到的Bitmap宽度是原图的1/3,高度也是原图的1/3。



二、脱离UI线程(Processing Bitmaps Off the UI Thread)

使用AsyncTask,在主线程中加载大量图片会导致,看起来机子很卡

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {    private final WeakReference<ImageView> imageViewReference;    private int data = 0;    public BitmapWorkerTask(ImageView imageView) {        // Use a WeakReference to ensure the ImageView can be garbage collected        imageViewReference = new WeakReference<ImageView>(imageView);  //使用弱引用    }    // Decode image in background.    @Override    protected Bitmap doInBackground(Integer... params) {        data = params[0];        return decodeSampledBitmapFromResource(getResources(), data, 100, 100));  //返回得到的图片    }    // Once complete, see if ImageView is still around and set bitmap.    @Override    protected void onPostExecute(Bitmap bitmap) {        if (imageViewReference != null && bitmap != null) {            final ImageView imageView = imageViewReference.get();              if (imageView != null) {    //由于是弱引用判断是否被回收再设置图片                imageView.setImageBitmap(bitmap);            }        }    }}



//-----------------------------------使用AsyncTask异步加载图片

public void loadBitmap(int resId, ImageView imageView) {    BitmapWorkerTask task = new BitmapWorkerTask(imageView);    task.execute(resId);}


三、缓存Bitmap(Caching Bitmaps)

1、使用内存缓存LruCache类(Use a Memory Cache)

2.3以后垃圾回收器,对于回收软引用和弱引用越来越厉害,往往,程序离out of memory 还很早弱引用或者软引用就被回收了。。

所以不建议使用软引用和弱引用。

下面的例子是使用 LruCache加载Bitmap

private LruCache<String, Bitmap>  mMemoryCache;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(new MyView(this));int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024);int cacheSize = maxMemory/8;  //缓存mMemoryCache = new LruCache<String, Bitmap>(cacheSize){@Overrideprotected int sizeOf(String key, Bitmap value) {return value.getByteCount()/1024;  //缓存的大小 ,兆为单位}};}//往内存缓存中加入图片public void addBitmapToMemoryCache(String key,Bitmap bitmap){mMemoryCache.put(key, bitmap);}//通过key得到Bitmappublic Bitmap  getBitmapFromMemoryCache(String key){return mMemoryCache.get(key);}    public void  loadImage(int resId ,ImageView mImageView){    final String imageKey = String.valueOf(resId);        final Bitmap bitmap = getBitmapFromMemoryCache(imageKey);        if (bitmap != null) {            mImageView.setImageBitmap(bitmap);        } else {            mImageView.setImageResource(R.drawable.image_placeholder);//设置默认图片            //异步加载图片            BitmapWorkerTask task = new BitmapWorkerTask(mImageView);            task.execute(resId);                   }    }



2、使用磁盘缓存(Use a Disk Cache)

public static File getDiskCacheDir(Context context, String uniqueName) {       final String cachePath =            Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||                    !isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :                            context.getCacheDir().getPath();    return new File(cachePath + File.separator + uniqueName);}


四、管理Bitmap内存(Managing Bitmap Memory)

五、显示Bitmap到你的UI(Displaying Bitmaps in Your UI)


0 0
原创粉丝点击