高效的加载图片整理
2017-07-04 22:37
155 查看
高效的加载图片
图片的缩放
AsyncTask 类提供了一个简单的方法来在后台线程执行一些操作,并且可以把后台的结果呈现到UI线程。下面是一个加载大
图的示例:
为ImageView使用WeakReference 确保了 AsyncTask 所引用的资源可以被GC(garbage collected)。因为当任务结束时不能
确保 ImageView 仍然存在,因此你必须在 onPostExecute() 里面去检查引用。这个ImageView 也许已经不存在了,例如,
在任务结束时用户已经不在那个Activity或者是设备已经发生配置改变(旋转屏幕等)。
开始异步加载位图,只需要创建一个新的任务并执行它即可:
处理并发问题(Handle Concurrency)
Multithreading for Performance 这篇博文更进一步的讨论了如何处理并发并且提供了一种解决方法,当任务结束时
ImageView 保存一个最近常使用的AsyncTask引用。使用类似的方法, AsyncTask 可以扩展出一个类似的模型。创建一个专
用的 Drawable 子类来保存一个可以回到当前工作任务的引用。在这种情况下,BitmapDrawable 被用来作为占位图片,它可
以在任务结束时显示到ImageView中。
创建一个专用的Drawable的子类来储存返回工作任务的引用。在这种情况下,当任务完成时BitmapDrawable会被使用,
placeholder image才会在ImageView中被显示:
在执行BitmapWorkerTask 之前,你需要创建一个 AsyncDrawable 并且绑定它到目标组件 ImageView 中:
在上面的代码示例中, cancelPotentialWork 方法检查确保了另外一个在ImageView中运行的任务得以取消。如果是这样,它
通过执行 cancel() 方法来取消之前的一个任务. 在小部分情况下, New出来的任务有可能已经存在,这样就不需要执行这个任
务了。下面演示了如何实现一个 cancelPotentialWork 。
在上面有一个帮助方法, getBitmapWorkerTask() , 被用作检索任务是否已经被分配到指定的 ImageView:
最后一步是在BitmapWorkerTask 的 onPostExecute() 方法里面做更新操作:
这个方法不仅仅适用于 ListView 与 GridView 组件,在那些需要循环利用子视图的组件中同样适用。只需要在设置图片到
ImageView的地方调用 loadBitmap 方法。例如,在GridView 中实现这个方法会是在 getView() 方法里面调用。
完整的示例代码:
声明:资源 摘自:Google Android官方培训教程中文版
图片的缩放
public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; 有效地加载大尺寸位图(Loading Large Bitmaps Efficiently) 读取位图的尺寸与类型(Read Bitmap Dimensions and Type) 加载一个按比例缩小的版本到内存中(Load a Scaled Down Version into Memory) final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
AsyncTask 类提供了一个简单的方法来在后台线程执行一些操作,并且可以把后台的结果呈现到UI线程。下面是一个加载大
图的示例:
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); } } } }
为ImageView使用WeakReference 确保了 AsyncTask 所引用的资源可以被GC(garbage collected)。因为当任务结束时不能
确保 ImageView 仍然存在,因此你必须在 onPostExecute() 里面去检查引用。这个ImageView 也许已经不存在了,例如,
在任务结束时用户已经不在那个Activity或者是设备已经发生配置改变(旋转屏幕等)。
开始异步加载位图,只需要创建一个新的任务并执行它即可:
public void loadBitmap(int resId, ImageView imageView) { BitmapWorkerTask task = new BitmapWorkerTask(imageView); task.execute(resId); }
处理并发问题(Handle Concurrency)
Multithreading for Performance 这篇博文更进一步的讨论了如何处理并发并且提供了一种解决方法,当任务结束时
ImageView 保存一个最近常使用的AsyncTask引用。使用类似的方法, AsyncTask 可以扩展出一个类似的模型。创建一个专
用的 Drawable 子类来保存一个可以回到当前工作任务的引用。在这种情况下,BitmapDrawable 被用来作为占位图片,它可
以在任务结束时显示到ImageView中。
创建一个专用的Drawable的子类来储存返回工作任务的引用。在这种情况下,当任务完成时BitmapDrawable会被使用,
placeholder image才会在ImageView中被显示:
static class AsyncDrawable extends BitmapDrawable { private final WeakReference bitmapWorkerTaskReference; public AsyncDrawable(Resources res, Bitmap bitmap,BitmapWorkerTask bitmapWorkerTask) { super(res, bitmap); bitmapWorkerTaskReference = new WeakReference(bitmapWorkerTask); } public BitmapWorkerTask getBitmapWorkerTask() { return bitmapWorkerTaskReference.get(); } }
在执行BitmapWorkerTask 之前,你需要创建一个 AsyncDrawable 并且绑定它到目标组件 ImageView 中:
public void loadBitmap(int resId, ImageView imageView) { if (cancelPotentialWork(resId, imageView)) { final BitmapWorkerTask task = new BitmapWorkerTask(imageView); final AsyncDrawable asyncDrawable = new AsyncDrawable(getResources(), mPlaceHolderBitmap, task); imageView.setImageDrawable(asyncDrawable); task.execute(resId); } }
在上面的代码示例中, cancelPotentialWork 方法检查确保了另外一个在ImageView中运行的任务得以取消。如果是这样,它
通过执行 cancel() 方法来取消之前的一个任务. 在小部分情况下, New出来的任务有可能已经存在,这样就不需要执行这个任
务了。下面演示了如何实现一个 cancelPotentialWork 。
public static boolean cancelPotentialWork(int data, ImageView imageView) { final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); if (bitmapWorkerTask != null) { final int bitmapData = bitmapWorkerTask.data; if (bitmapData == 0 || bitmapData != data) { // Cancel previous task bitmapWorkerTask.cancel(true); } else { // The same work is already in progress return false; } } // No task associated with the ImageView, or an existing task was cancelled return true; }
在上面有一个帮助方法, getBitmapWorkerTask() , 被用作检索任务是否已经被分配到指定的 ImageView:
private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { if (imageView != null) { final Drawable drawable = imageView.getDrawable(); if (drawable instanceof AsyncDrawable) { final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; return asyncDrawable.getBitmapWorkerTask(); } } return null; }
最后一步是在BitmapWorkerTask 的 onPostExecute() 方法里面做更新操作:
class BitmapWorkerTask extends AsyncTask { ... @Override protected void onPostExecute(Bitmap bitmap) { if (isCancelled()) { bitmap = null; } if (imageViewReference != null && bitmap != null) { final ImageView imageView = imageViewReference.get(); final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); if (this == bitmapWorkerTask && imageView != null) { imageView.setImageBitmap(bitmap); } } } }
这个方法不仅仅适用于 ListView 与 GridView 组件,在那些需要循环利用子视图的组件中同样适用。只需要在设置图片到
ImageView的地方调用 loadBitmap 方法。例如,在GridView 中实现这个方法会是在 getView() 方法里面调用。
BitmapWorkerTask task = new BitmapWorkerTask(mImageView); task.execute(resId);
完整的示例代码:
private class ImageAdapter extends BaseAdapter {
...
@Override
public View getView(int position, View convertView, ViewGroup container) {
...
loadBitmap(imageResIds[position], imageView)
return imageView;
}
public void loadBitmap(int resId, ImageView imageView) { if (cancelPotentialWork(resId, imageView)) { final BitmapWorkerTask task = new BitmapWorkerTask(imageView); final AsyncDrawable asyncDrawable = new AsyncDrawable(getResources(), mPlaceHolderBitmap, task); imageView.setImageDrawable(asyncDrawable); task.execute(resId); } }
static class AsyncDrawable extends BitmapDrawable { private final WeakReference bitmapWorkerTaskReference; public AsyncDrawable(Resources res, Bitmap bitmap,BitmapWorkerTask bitmapWorkerTask) { super(res, bitmap); bitmapWorkerTaskReference = new WeakReference(bitmapWorkerTask); } public BitmapWorkerTask getBitmapWorkerTask() { return bitmapWorkerTaskReference.get(); } }
public static boolean cancelPotentialWork(int data, ImageView imageView) {
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (bitmapWorkerTask != null) {
final int bitmapData = bitmapWorkerTask.data;
if (bitmapData != data) {
// Cancel previous task
bitmapWorkerTask.cancel(true);
} else {
// The same work is already in progress
return false;
}
}
// No task associated with the ImageView, or an existing task was cancelled
return true;
}
private static BitmapWorkerTask getBitmapWorkerTask(ImageView
4000
imageView) {
if (imageView != null) {
final Drawable drawable = imageView.getDrawable();
if (drawable instanceof AsyncDrawable) {
final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
return asyncDrawable.getBitmapWorkerTask();
}
}
return null;
}
}
声明:资源 摘自:Google Android官方培训教程中文版
相关文章推荐
- Android内存溢出整理总结 OOM(Out Of Memory) 加载的图片太多或图片过大时经常出现OOM问题
- 高效地显示Bitmap图片 1 - 有效率地加载大尺寸的位图
- 图片缓存LruCache 高效加载图片 学习笔记 + 开源项目:DiskLruCache
- Android高效加载图片,有效避免程序OOM
- 高效地加载图片(三) 缓存图片
- 【Android Training - 09】高效地显示Bitmap图片 [ Lesson 1 - 有效率地加载大尺寸的位图]
- Android 高效加载大图片
- Android高效加载大图、多图解决方案,有效避免程序OOM(使用LruCache 强引缓存图片用取代软引用)
- 利用CSS、JavaScript及Ajax实现高效的图片预加载
- 高效地加载图片(五) 将图片展示在UI中
- Android--高效地加载大图片
- 关于android示例程序(bitmapfun)——高效加载图片的坑爹地方
- lazyload 图片加载插件 整理
- Android 高效加载大图片(缓存机制)
- 关于android示例程序(bitmapfun)——高效加载图片的缺陷
- Android中高效的显示图片之一 ——加载大图
- android高效加载大图片
- Anroid高效显示Bitmap图片,减少OOM问题,加载大尺寸位图
- 高效地加载图片(一) 高效地加载大图
- 连载 1 - 深入讨论 Android 关于高效显示图片的问题 - 如何高效的加载大位图