按需加载
inJustDecodeBounds
BitmapFactory.Options.inJustDecodeBounds
设置为 true
就可以让解析方法禁止为bitmap分配内存,返回值也不再是一个Bitmap对象,而是null。
虽然 Bitmap 是 null 了,但是 BitmapFactory.Options的outWidth、outHeight 和 outMimeType 属性都会被赋值
考虑因素
- 预估一下加载整张图片所需占用的内存;
- 为了加载这一张图片你所愿意提供多少内存;
- 用于展示这张图片的控件的实际大小;
- 当前设备的屏幕尺寸和分辨率
比如,你的 ImageView 只有128x96
像素的大小,只是为了显示一张缩略图,这时候把一张1024x768
像素的图片完全加载到内存中显然是不值得的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } return inSampleSize; }
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); }
mImageView.setImageBitmap( decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
|
图片缓存-LruCache
考虑因素
- 设备可以为每个应用程序分配多大的内存;
- 设备屏幕上一次最多能显示多少张图片?有多少图片需要进行预加载;
- 设备的屏幕大小和分辨率分别是多少?一个超高分辨率的设备(例如 1080P、1440P) 比起一个较低分辨率的设备(例如 480P、720P),在持有相同数量图片的时候,需要更大的缓存空间;
- 图片的尺寸和大小,还有每张图片会占据多少内存空间;
- 图片被访问的频率有多高?会不会有一些图片的访问频率比其它图片要高?如果有的话,也许应该让一些图片常驻在内存当中,或者使用多个LruCache 对象来区分不同组的图片;
- 能维持好数量和质量之间的平衡吗?有些时候,存储多个低像素的图片,而在后台去开线程加载高像素的图片会更加的有效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| private LruCache<String, Bitmap> mMemoryCache; @Override protected void onCreate(Bundle savedInstanceState) { int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); int cacheSize = maxMemory / 8; mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { return bitmap.getByteCount() / 1024; } }; } public void loadBitmap(int resId, ImageView imageView) { final String imageKey = String.valueOf(resId); final Bitmap bitmap = getBitmapFromMemCache(imageKey); if (bitmap != null) { imageView.setImageBitmap(bitmap); } else { imageView.setImageResource(R.drawable.image_placeholder); BitmapWorkerTask task = new BitmapWorkerTask(imageView); task.execute(resId); } }
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { @Override protected Bitmap doInBackground(Integer... params) { final Bitmap bitmap = decodeSampledBitmapFromResource( getResources(), params[0], 100, 100); addBitmapToMemoryCache(String.valueOf(params[0]), bitmap); return bitmap; } }
|