Android引入高速缓存的异步加载全分辨率
Android引进高速缓存的异步加载全分辨率
为什么要缓存
内存缓存
内存缓存技术对那些大量占用应用程序宝贵内存的图片提供了高速訪问的方法。当中最核心的类是LruCache 。这个类非常适合用来缓存图片,它的主要算法原理是把近期使用的对象用强引用存储在 LinkedHashMap 中,并且把近期最少使用的对象在缓存值达到预设定值之前从内存中移除。LruCache 是在support-v4中才引入的,在引入LruCache 之前。Google建议的是使用软引用或弱引用 (SoftReference or WeakReference)来进行内存缓存。可是从Android 2.3開始,GC算法改动,软引用与弱引用相同会优先被GC回收。所以这样的方法也就没有太高的使用价值了,如今网上非常多还在继续使用SoftReference 和WeakReference的文章。大多都是过时的文章,建议大家跟上党的步伐,与时俱进。
LruCache使用
这个平衡点常常须要非常多经验和測试来决定。
使用LruCache非常easy:
private LruCache<String, Bitmap> mMemoryCaches; // 获取应用内存
int maxMemory = (int) Runtime.getRuntime().maxMemory();
// 分配cache
int cacheSize = maxMemory / 10;
mMemoryCaches = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
}; // 从LruCache获取中获取缓存对象
public Bitmap getBitmapFromMemoryCaches(String url) {
return mMemoryCaches.get(url);
} // 添加缓存对象到LruCache
public void addBitmapToMemoryCaches(String url,Bitmap bitmap) {
if (getBitmapFromMemoryCaches(url) == null) {
mMemoryCaches.put(url, bitmap);
}
}
首先,我们须要声明LruCache。接着。通过LruCache的构造方法创建缓存对象,并为其分配cacheSize,这个cacheSize通常我们须要通过Runtime来获取,获取当前系统分给App的可用内存,并将这些内存的一部分用做LruCache缓存。LruCache中必须重写sizeOf方法。通过这种方法,LruCache能够获取每一个缓存对象的大小。子类必须重写。由于默认的LruCache获取的是缓存的个数。
。。尼玛。
为异步处理添加一级缓存
滚完再载入
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE) {
mImageLoader.loadImages(mStart, mEnd);
} else {
mImageLoader.cancelAllTasks();
}
} @Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
mStart = firstVisibleItem;
mEnd = firstVisibleItem + visibleItemCount;
if (mFirstFlag && visibleItemCount > 0) {
mImageLoader.loadImages(mStart, mEnd);
mFirstFlag = false;
}
}
载入显示的项目
public void loadImages(int start, int end) {
for (int i = start; i < end; i++) {
String url = Images.IMAGE_URLS[i];
Bitmap bitmap = getBitmapFromMemoryCaches(url);
if (bitmap == null) {
ASyncDownloadImage task = new ASyncDownloadImage(url);
mTasks.add(task);
task.execute(url);
} else {
ImageView imageView = (ImageView) mListView.findViewWithTag(url);
imageView.setImageBitmap(bitmap);
}
}
}
这里我们在设置图片的时候,直接通过findViewWithTag。通过url来找到相应的Imageview,这里与之前不同是由于我们这里是依照start到end来进行载入,直接从ListView对象中获取相应的Imageview比較简单。
下载与Asynctask
private static Bitmap getBitmapFromUrl(String urlString) {
Bitmap bitmap;
InputStream is = null;
try {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
is = new BufferedInputStream(conn.getInputStream());
bitmap = BitmapFactory.decodeStream(is);
conn.disconnect();
return bitmap;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null)
is.close();
} catch (IOException e) {
}
}
return null;
}
Asynctask也与之前基本相似:
class ASyncDownloadImage extends AsyncTask<String, Void, Bitmap> {
private String url;
public ASyncDownloadImage(String url) {
this.url = url;
}
@Override
protected Bitmap doInBackground(String... params) {
url = params[0];
Bitmap bitmap = getBitmapFromUrl(url);
if (bitmap != null) {
addBitmapToMemoryCaches(url, bitmap);
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
ImageView imageView = (ImageView) mListView.findViewWithTag(url);
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
mTasks.remove(this);
}
}
唯一不同的是。我们在下载好图像之后。会将图像载入到Lrucache。
组装
package com.imooc.listviewacyncloader; import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.LruCache;
import android.widget.ImageView;
import android.widget.ListView; import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashSet;
import java.util.Set; public class ImageLoaderWithCaches { private Set<ASyncDownloadImage> mTasks;
private LruCache<String, Bitmap> mMemoryCaches;
private ListView mListView; public ImageLoaderWithCaches(ListView listview) {
this.mListView = listview;
mTasks = new HashSet<>();
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheSize = maxMemory / 10;
mMemoryCaches = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
};
} public void showImage(String url, ImageView imageView) {
Bitmap bitmap = getBitmapFromMemoryCaches(url);
if (bitmap == null) {
imageView.setImageResource(R.drawable.ic_launcher);
} else {
imageView.setImageBitmap(bitmap);
}
} public Bitmap getBitmapFromMemoryCaches(String url) {
return mMemoryCaches.get(url);
} public void addBitmapToMemoryCaches(String url,Bitmap bitmap) {
if (getBitmapFromMemoryCaches(url) == null) {
mMemoryCaches.put(url, bitmap);
}
} public void loadImages(int start, int end) {
for (int i = start; i < end; i++) {
String url = Images.IMAGE_URLS[i];
Bitmap bitmap = getBitmapFromMemoryCaches(url);
if (bitmap == null) {
ASyncDownloadImage task = new ASyncDownloadImage(url);
mTasks.add(task);
task.execute(url);
} else {
ImageView imageView = (ImageView) mListView.findViewWithTag(url);
imageView.setImageBitmap(bitmap);
}
}
} private static Bitmap getBitmapFromUrl(String urlString) {
Bitmap bitmap;
InputStream is = null;
try {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
is = new BufferedInputStream(conn.getInputStream());
bitmap = BitmapFactory.decodeStream(is);
conn.disconnect();
return bitmap;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null)
is.close();
} catch (IOException e) {
}
}
return null;
} public void cancelAllTasks() {
if (mTasks != null) {
for (ASyncDownloadImage task : mTasks) {
task.cancel(false);
}
}
} class ASyncDownloadImage extends AsyncTask<String, Void, Bitmap> { private String url; public ASyncDownloadImage(String url) {
this.url = url;
} @Override
protected Bitmap doInBackground(String... params) {
url = params[0];
Bitmap bitmap = getBitmapFromUrl(url);
if (bitmap != null) {
addBitmapToMemoryCaches(url, bitmap);
}
return bitmap;
} @Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
ImageView imageView = (ImageView) mListView.findViewWithTag(url);
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
mTasks.remove(this);
}
}
}
以下是Adapter的代码:
package com.imooc.listviewacyncloader; import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView; import java.util.List; public class MyAdapterUseCaches extends BaseAdapter implements
AbsListView.OnScrollListener { private LayoutInflater mInflater;
private List<String> mData;
private ImageLoaderWithCaches mImageLoader;
private int mStart = 0, mEnd = 0;
private boolean mFirstFlag; public MyAdapterUseCaches(Context context, List<String> data, ListView listView) {
this.mData = data;
mInflater = LayoutInflater.from(context);
mImageLoader = new ImageLoaderWithCaches(listView);
mImageLoader.loadImages(mStart, mEnd);
mFirstFlag = true;
listView.setOnScrollListener(this);
} @Override
public int getCount() {
return mData.size();
} @Override
public Object getItem(int position) {
return mData.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
String url = mData.get(position);
ViewHolder viewHolder = null;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.listview_item, null);
viewHolder.imageView =
(ImageView) convertView.findViewById(R.id.iv_lv_item);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.imageView.setTag(url);
viewHolder.imageView.setImageResource(R.drawable.ic_launcher);
mImageLoader.showImage(url, viewHolder.imageView);
return convertView;
} @Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE) {
mImageLoader.loadImages(mStart, mEnd);
} else {
mImageLoader.cancelAllTasks();
}
} @Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
mStart = firstVisibleItem;
mEnd = firstVisibleItem + visibleItemCount;
if (mFirstFlag && visibleItemCount > 0) {
mImageLoader.loadImages(mStart, mEnd);
mFirstFlag = false;
}
} public class ViewHolder {
public ImageView imageView;
}
}
是不是非常easy,如今引入缓存了,下载过的图片会临时保存在内存中。妈妈再也不用操心你OOM啦。

版权声明:本文博主原创文章。博客,未经同意不得转载。
Android引入高速缓存的异步加载全分辨率的更多相关文章
- [Android Pro] 使用CursorLoader异步加载数据 from 3.0
Android 3.0引入了CursorLoader实现异步加载数据,为了避免同步查询数据库时阻塞UI线程的问题.在API 11之前可以通过下载支持库,来使之前的系统支持此功能,下载页面为 http: ...
- Android之使用Android-AQuery异步加载图片(一)
第一节:转载地址(http://www.cnblogs.com/lee0oo0/archive/2012/10/25/2738299.html) // 必须实现AQuery这个类 AQuery aq ...
- (转)Android技术积累:图片异步加载
当在ListView或GridView中要加载很多图片时,很容易出现滑动时的卡顿现象,以及出现OOM导致FC(Force Close). 会出现卡顿现象主要是因为加载数据慢,要等数据加载完才能显示出来 ...
- Android中图片的异步加载
转: 1. 为什么要异步加载图片 下载图片比较费时,先显示文字部分,让加载图片的过程在后台,以提升用户体验 2. SoftReference的作用 栈内存—引用 堆内存—对象 Eg: Object ...
- Android异步加载图像(含线程池,缓存方法)
研究了android从网络上异步加载图像: (1)由于android UI更新支持单一线程原则,所以从网络上取数据并更新到界面上,为了不阻塞主线程首先可能会想到以下方法. 在主线程中new 一个Han ...
- 转: Android异步加载图像小结
转:http://blog.csdn.net/sgl870927/article/details/6285535 研究了android从网络上异步加载图像,现总结如下: (1)由于android UI ...
- Android图片异步加载之Android-Universal-Image-Loader
将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就 ...
- [置顶] Android图片异步加载之Android-Universal-Image-Loader
将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就 ...
- ListView与GridView异步加载图片
原理很简单,主要是用到了回调方法,下面是异步加载图片的类 <span style="font-size:16px;">package com.xxx.xxx; impo ...
随机推荐
- HTML5:footer定位(底部+居中)的探讨+div图片居中问题
初学HTML+CSS布局,尝试自己写一个百度首页,可是footer的定位遇到麻烦而且百度没有好的解决方法,在此记录下逐步的过程.记录之,备忘. 初学,解决方法难免出现不妥之处,也请看到这篇文章的前辈指 ...
- MBR格式无法识别2T以上的硬盘的问题
早上有人打电话说四块2T的sata 硬盘做了raid 5之后安装window server 2012的时候,无法创建分区,安装完系统后无法给剩余的硬盘创建分区,刚开始的时候我还以为是别人分区的数量问题 ...
- svn rm --keep-local ./QueryParser_kill.logs
svn rm --keep-local ./QueryParser_kill.logs
- OpenCV 通过 MFC 的 Picture Control 控件操作图像
假设希望对显示在MFC Picture Control 控件里的图像进行操作,比方画线画点之类的,能够利用 OpenCV 结合 MFC 本身的鼠标响应函数来实现. 怎样将图像显示到 Picture C ...
- ORA-00600: 内部错误代码, 参数: [kqlnrc_1]
如以下的错误: Mon Mar 31 18:45:59 2014 Errors in file /oracle/app/oracle/diag/rdbms/zscims/zscims2/trace/z ...
- centos6搭建本地openstack软件源
1.把相关软件包所有下载到本地机器 wget -np -nH –cut-dirs=1 -r -c -L –exclude-directories=repodata –accept=rpm,gz,xml ...
- 《Android内核剖析》读书笔记 第13章 View工作原理【View树遍历】
View状态分类 在View视图中定义了多种和界面效果相关的状态,比如拥有焦点Focused.按下Pressed等,不同的状态一般会显示不同的界面效果,而且视图状态会随着用户的操作而改变,一般通过xm ...
- 《JavaScript设计模式与开发实践》读书笔记之享元模式
1. 享元模式 享元模式是一种用于性能优化的模式,享元模式的核心是运用共享技术来有效支持大量细粒度的对象 1.1 传统的文件上传方法 以文件上传为例,文件上传功能可以选择依照队列,一个一个的排队上传, ...
- 如何让HTML在手机上实现直接拨打电话以及发送短信?
拨打电话的HTML实现方式: <a href="tel:134289210xx″>拨打电话</a> 上面是比较常用的方式,但是有可能在某些场景下是支持不太好,可以试用 ...
- phpmailer【PHP邮件】的用法
第一,需要下载PHPMailer文件包phpmailer. http://phpmailer.sourceforge.net/ 第二,确认你的服务器系统已经支持socket ,通过phpinfo(); ...