您的位置:首页 > 移动开发 > Android开发

Android高效显示图片详解(三)

2015-06-30 11:39 423 查看


Android高效显示图片详解(三)

分类: Android2013-03-16
22:50 3949人阅读 评论(5) 收藏 举报

Android图片溢出高效内存

用户在使用ListView或GridView时,控件会自动把用户滑过的已不在当前显示区域的ChildView回收掉,当然也会把该子视图上的bitmap回收掉以释放内存,因此,为了保证一个流畅,快速的操作体验,我们应当避免反复的对同一张图片进行加载,比如说用户在往下看图的过程中又向上滑回去看图,这时对于已经上面已经加载过的图片我们就没有必要让它再加载一遍了,应该能很快的把图片显示出来,这里我们要使用缓存来达到这一目的。

一,使用Memory Cache:

内存缓存速度快,同时为了更加适应实际应用的场景,我们使用LruCache来达到按使用频率缓存的目的,把最近使用的加入缓存,较长时间不用的则会剔除掉释放出空间。

缓存的代码如下:

[html] view
plaincopy

private LruCache<String, Bitmap> mMemoryCache;

@Override

protected void onCreate(Bundle savedInstanceState) {

...

// Get max available VM memory, exceeding this amount will throw an

// OutOfMemory exception. Stored in kilobytes as LruCache takes an

// int in its constructor.

final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

// Use 1/8th of the available memory for this memory cache.

final int cacheSize = maxMemory / 8;

mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {

@Override

protected int sizeOf(String key, Bitmap bitmap) {

// The cache size will be measured in kilobytes rather than

// number of items.

return bitmap.getByteCount() / 1024;

}

};

...

}

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {

if (getBitmapFromMemCache(key) == null) {

mMemoryCache.put(key, bitmap);

}

}

public Bitmap getBitmapFromMemCache(String key) {

return mMemoryCache.get(key);

}

那么我们在loadBitmap的时候就可以先检查下缓存中保存的是否有该图片,有则直接取出使用,不再进行加载。

新的代码如下:

[html] view
plaincopy

public void loadBitmap(int resId, ImageView imageView) {

final String imageKey = String.valueOf(resId);

final Bitmap bitmap = getBitmapFromMemCache(imageKey);

if (bitmap != null) {

mImageView.setImageBitmap(bitmap);

} else {

mImageView.setImageResource(R.drawable.image_placeholder);

BitmapWorkerTask task = new BitmapWorkerTask(mImageView);

task.execute(resId);

}

}

当然,我们也要在加载图片是及时的维护缓存,把刚使用到的图片add进缓存中去。

新的代码如下:

[html] view
plaincopy

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {

...

// Decode image in background.

@Override

protected Bitmap doInBackground(Integer... params) {

final Bitmap bitmap = decodeSampledBitmapFromResource(

getResources(), params[0], 100, 100));

addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);

return bitmap;

}

...

}

在使用内存做缓存的基础上,我们还可以使用Disk控件做为缓存,构成一种二级缓存的结构,设想这种情况,如果App在使用的过程被突然来电打断,那么此时有可能就会引起系统内存的回收,当用户再次切换到App时,App就要进行次很明显的图片再次加载的过程。这个时候,我们就需要用到Disk了,因为足够持久。

下面是是原来的基础上增加使用Disk Cache 的例子:

[html] view
plaincopy

private DiskLruCache mDiskLruCache;

private final Object mDiskCacheLock = new Object();

private boolean mDiskCacheStarting = true;

private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB

private static final String DISK_CACHE_SUBDIR = "thumbnails";

@Override

protected void onCreate(Bundle savedInstanceState) {

...

// Initialize memory cache

...

// Initialize disk cache on background thread

File cacheDir = getDiskCacheDir(this, DISK_CACHE_SUBDIR);

new InitDiskCacheTask().execute(cacheDir);

...

}

class InitDiskCacheTask extends AsyncTask<File, Void, Void> {

@Override

protected Void doInBackground(File... params) {

synchronized (mDiskCacheLock) {

File cacheDir = params[0];

mDiskLruCache = DiskLruCache.open(cacheDir, DISK_CACHE_SIZE);

mDiskCacheStarting = false; // Finished initialization

mDiskCacheLock.notifyAll(); // Wake any waiting threads

}

return null;

}

}

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {

...

// Decode image in background.

@Override

protected Bitmap doInBackground(Integer... params) {

final String imageKey = String.valueOf(params[0]);

// Check disk cache in background thread

Bitmap bitmap = getBitmapFromDiskCache(imageKey);

if (bitmap == null) { // Not found in disk cache

// Process as normal

final Bitmap bitmap = decodeSampledBitmapFromResource(

getResources(), params[0], 100, 100));

}

// Add final bitmap to caches

addBitmapToCache(imageKey, bitmap);

return bitmap;

}

...

}

public void addBitmapToCache(String key, Bitmap bitmap) {

// Add to memory cache as before

if (getBitmapFromMemCache(key) == null) {

mMemoryCache.put(key, bitmap);

}

// Also add to disk cache

synchronized (mDiskCacheLock) {

if (mDiskLruCache != null && mDiskLruCache.get(key) == null) {

mDiskLruCache.put(key, bitmap);

}

}

}

public Bitmap getBitmapFromDiskCache(String key) {

synchronized (mDiskCacheLock) {

// Wait while disk cache is started from background thread

while (mDiskCacheStarting) {

try {

mDiskCacheLock.wait();

} catch (InterruptedException e) {}

}

if (mDiskLruCache != null) {

return mDiskLruCache.get(key);

}

}

return null;

}

// Creates a unique subdirectory of the designated app cache directory. Tries to use external

// but if not mounted, falls back on internal storage.

public static File getDiskCacheDir(Context context, String uniqueName) {

// Check if media is mounted or storage is built-in, if so, try and use external cache dir

// otherwise use internal cache dir

final String cachePath =

Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||

!isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :

context.getCacheDir().getPath();

return new File(cachePath + File.separator + uniqueName);

}

版权声明:本文为博主原创文章,未经博主允许不得转载。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: