官方文档解决办法: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 {
private final WeakReference imageViewReference;
private int data = 0;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference(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 mMemoryCache;
@Override
protected 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(cacheSize){
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount()/1024; //缓存的大小 ,兆为单位
}
};
}
//往内存缓存中加入图片
public void addBitmapToMemoryCache(String key,Bitmap bitmap){
mMemoryCache.put(key, bitmap);
}
//通过key得到Bitmap
public 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)