“JANE”通过精心收集,向本站投稿了6篇Android异步加载学习笔记之四:利用缓存优化网络加载,下面是小编整理后的Android异步加载学习笔记之四:利用缓存优化网络加载,欢迎大家阅读分享借鉴,希望对大家有所帮助。

篇1:Android异步加载学习笔记之四:利用缓存优化网络加载
如果不做任何处理,直接用网络加载图片在网速快的情况下可能没什么不好的感觉,但是如果使用移动流量或是网络不好的时候,问题就来了,要么用户会抱怨流量使用太多,要么抱怨图片加载太慢,如论从哪个角度出发,都不是好的体验!要提高用户体验,我们就要使用缓存,今天学习是是Lru缓存。
Lru(Least Recently Used)近期最少使用算法,即是在一定条件下LRU缓存是把最近最少使用的数据移除,让给最新读取的数据。而往往最常读取的,也是读取次数最多的,所以,利用LRU缓存,我们能够提高应用的效率及用户体验度。Andorid本身提供了LruCache类来实现这个缓存算法 。
在ImageLoader中利用LruCache缓存:
public class ImageLoader {
private LruCache
private ImageView mImageView;
private ListView listView;
private Set
@SuppressLint(NewApi)
public ImageLoader(ListView listView) {
this.listView = listView;
mTask = new HashSet
int maxMemory = (int) Runtime.getRuntime().maxMemory();// 获取最大可用内存
int cacheSize = maxMemory / 8;// 设置缓存数据的最大占用内存量为最大值1/8
mCaches = new LruCache
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();// 每次存入缓存的时候调用,返回bitmap的大小
}
};
}
@SuppressLint(NewApi)
/**
* 增加缓存数据,增加前判断数据是否存在
* @description:
* @author ldm
* @date -8-11 下午7:51:04
*/
public void setLruCaches(String url, Bitmap bitmap) {
if (getLruCaches(url) == null) {// 如果缓存中不存在url对应的Bitmap,则把bitmap加入mCaches
mCaches.put(url, bitmap);
}
}
/**
* 从缓存中获取数据
* @description:
* @author ldm
* @date 2015-8-11 下午7:51:22
*/
@SuppressLint(NewApi)
public Bitmap getLruCaches(String url) {
return mCaches.get(url);// 通过url获取缓存中对应的bitmap
}
/**
*从url中获取到Bitmap
* @description:
* @author ldm
* @date 2015-8-11 下午1:55:12
*/
public Bitmap getBitmapByUrl(String urlStr) {
Bitmap bitmap = null;
InputStream is = null;
try {
URL url = new URL(urlStr);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
is = new BufferedInputStream(con.getInputStream());
bitmap = BitmapFactory.decodeStream(is);
con.disconnect();
return bitmap;
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
is.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
public void loadImgByAsyncTask(ImageView img, String url) {
mImageView = img;
// 从缓存中取出图片
Bitmap bitmap = getLruCaches(url);
if (bitmap == null) {// 如果能在中无图片,则就从网络下载
mImageView.setImageResource(R.drawable.ic_launcher);//设置默认图片
new ImageAsyncTask(url).execute(url);
}
else {// 缓存中有图片,则直接显示出来
mImageView.setImageBitmap(bitmap);
}
}
private class ImageAsyncTask extends AsyncTask
private ImageView imageView;
private String mUrl;
public ImageAsyncTask(String mUrl) {
this.mUrl = mUrl;
}
@Override
protected Bitmap doInBackground(String... params) {
Bitmap bitmap = getBitmapByUrl(params[0]);// 获取图片
if (bitmap != null) {
setLruCaches(params[0], bitmap);
}
return getBitmapByUrl(params[0]);
}
@Override
protected void onPostExecute(Bitmap result) {
ImageView img = (ImageView) listView.findViewWithTag(mUrl);
if (img != null && result != null) {
imageView.setImageBitmap(result);
}
mTask.remove(this);
}
}
public void setImageView(int start, int end) {
for (int i = start; i < end; i++) {
String url = DataAdapter.URLS[i];
Bitmap bitmap = getLruCaches(url);
if (bitmap == null) {// 如果能在中无图片,则就从网络下载
ImageAsyncTask task = new ImageAsyncTask(url);
task.execute(url);
mTask.add(task);
}
else {// 缓存中有图片,则直接显示出来
ImageView img = (ImageView) listView.findViewWithTag(url);
img.setImageBitmap(bitmap);
}
}
}
public void stopAllTask(){
if(mTask.size()>0){
for (ImageAsyncTask task : mTask) {
task.cancel(false);
}
}
}
}
对应ListView的数据适配器DataAdapter:
public class DataAdapter extends BaseAdapter implements OnScrollListener {
private Context mContext;
private List
private ImageLoader mImageLoader;
private int mSart;
private int mEnd;
public static String[] URLS;
private ListView listView;
private boolean isFirst;//是否是第一次进入
public DataAdapter(Context mContext, List
this.listView = listView;
this.mContext = mContext;
this.list = list;
mImageLoader = new ImageLoader(listView);
URLS = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
URLS[i] = list.get(i).getImgUrl();
}
isFirst=true;
listView.setOnScrollListener(this);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return list.get(arg0);
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
@Override
public View getView(int arg0, View view, ViewGroup arg2) {
ViewHolder holder = null;
if (view == null) {
holder = new ViewHolder();
view = LayoutInflater.from(mContext).inflate(R.layout.item_layout, null);
holder.iv = (ImageView) view.findViewById(R.id.item_iv);
holder.titleTv = (TextView) view.findViewById(R.id.item_title);
holder.contentTv = (TextView) view.findViewById(R.id.item_content);
view.setTag(holder);
}
else {
holder = (ViewHolder) view.getTag();
}
holder.titleTv.setText(list.get(arg0).getTitle());
holder.contentTv.setText(list.get(arg0).getContent());
holder.iv.setTag(list.get(arg0).getImgUrl());// 为ImageView设置tag
// new ImageLoader().loaderImageThread(holder.iv, list.get(arg0).getImgUrl());//用线程加载图片
mImageLoader.loadImgByAsyncTask(holder.iv, list.get(arg0).getImgUrl());
return view;
}
/***
* ListView在流动过程中调用
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
mSart = firstVisibleItem;// 可见第一个item
mEnd = firstVisibleItem + visibleItemCount;// 可见的最后一个item
if(isFirst&&visibleItemCount>0){//第一次加载数据时数据处理
mImageLoader.setImageView(mSart, mEnd);
isFirst=false;
}
}
/***
* ListView在流动状态变化时调用
*/
@Overridewww.2cto.com
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE) {// 流动停止,此时加载可见项数据
mImageLoader.setImageView(mSart, mEnd);
}
else {// 停止加载数据
mImageLoader.stopAllTask();
}
}
class ViewHolder {
TextView titleTv;
TextView contentTv;
ImageView iv;
}
}
篇2:Android异步加载全解析之引入一级缓存
通过对图像的缩放,我们做到了对大图的异步加载优化,但是现在的App不仅是高清大图,更是高清多图,动不动就是图文混排,以图代文,如果这些图片都加载到内存中,必定会OOM,因此,在用户浏览完图像后,应当立即将这些废弃的图像回收,但是,这又带来了另一个问题,也就是当用户在浏览完一次图片后,如果还要返回去再进行重新浏览,那么这些回收掉的图像又要重新进行加载,保不准就要那些无聊到 的人在那一边看你回收GC,一边看你重新加载。这两件事情,肯定是互相矛盾的,也是影响性能的一个很重要的原因。
篇3:Android异步加载全解析之引入一级缓存
内存缓存LruCache所使用的内存缓存大小是由开发者决定的,开发者需要根据图像的使用率、分辨率、访问频率、设备性能等很多因素进行考虑。这个平衡点经常需要很多经验和测试来决定。使用LruCache非常简单:
private LruCache
首先,我们需要声明LruCache,接着,通过LruCache的构造方法创建缓存对象,并为其分配cacheSize,这个cacheSize通常我们需要通过Runtime来获取,获取当前系统分给App的可用内存,并将这些内存的一部分用做LruCache缓存。LruCache中必须重写sizeOf方法,通过这个方法,LruCache可以获取每个缓存对象的大小,子类必须重写,因为默认的LruCache获取的是缓存的个数。。。 。 最后,我们提供两个方法getBitmapFromMemoryCaches和addBitmapToMemoryCaches分别用来获取和增加内存缓存到LruCache。 等等,我们好像还没写释放内存的方法,对,不用你写了,Lru算法可以保证cacheSize不会OOM,一旦超过这个大小,GC就会回收时间最长的对象,释放空间。
篇4:Android异步加载全解析之引入一级缓存
针对这样一个非常需要找到一个彼此平衡点的问题,Google提供了一套内存缓存技术。内存缓存技术对那些大量占用应用程序宝贵内存的图片提供了快速访问的方法。其中最核心的类是LruCache 。这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。LruCache 是在support-v4中才引入的,在引入LruCache 之前,Google建议的是使用软引用或弱引用 (SoftReference or WeakReference)来进行内存缓存。但是从Android 2.3开始,GC算法修改,软引用与弱引用同样会优先被GC回收,所以这种方法也就没有太高的使用价值了,现在网上很多还在继续使用SoftReference 和WeakReference的文章,大多都是过时的文章,建议大家跟上党的步伐,与时俱进。
篇5:Android异步加载全解析之引入一级缓存
OK,在了解了关于缓存的基础信息后,我们回到现在这个例子,想想怎么利用缓存来进行异步处理的优化。首先,ListView、GridView这些娇生惯养的玩意儿,碰不得摔不得,更不能在它滚的开心的时候,你还在后面拼命玩加载。所以,第一个重点,滚的时候就让它开心的滚,滚完了再开始加载。
滚完再加载
要实现这一点,我们可以通过给Adapter增加AbsListView.OnScrollListener接口来实现。 当然,还有一点需要注意,第一次初始化的时候,一定要手动来加载图片,不然系统判断你没滚,只能调用onScroll方法,不会调用onScrollStateChanged方法。而且我们也需要在onScroll方法中来不断获取可见的Item。特别要注意的是visibleItemCount,只要大于0的时候,才认为是开始显示图片了。
@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) { if (scrollState == SCROLL_STATE_IDLE) { mImageLoader.loadImages(mStart, mEnd); } else { mImageLoader.cancelAllTasks; }}@Overridepublic 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; }}
加载显示的项目
加载数据的时候,获取第一个能显示的Item和最后一个可见的Item,只加载这一部分。所以我们创建一个方法——loadImages(int start, int end)。这个方法用来加载从start到end之间的Item数据。 加载的时候,先从内存缓存中去取,如果有,那说明最近已经加载过了,那直接加载就好了,如果没有取到,那就开启synctask去下载。
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
唯一不同的是,我们在下载好图像之后,会将图像加载到Lrucache。
组装
OK,万事具备,准备刷代码。在刷之前,我们先来重新整理下思路,首先,在Adapter中,一加载ListView,就开始下载显示范围内的Item的图像,这时候缓存中当然没有,所以都去下载了,下完了就显示在Item中,并缓存起来,如果还没下完,你就迫不及待的滚起来了,那么立即取消所有task,让ListView欢快的滚,滚完之后,继续加载。 OK,该讲的都讲了,下面我们开始刷代码了,一切尽在不言中,只有代码最懂你。
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 mTasks; private LruCache
下面是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
是不是非常简单,现在引入缓存了,下载过的图片会暂时保存在内存中,妈妈再也不用担心你OOM啦,
我们下拉试试,下载完的图片再次出现也可以马上加载了,除非滑动太多导致GC。
可以就看见,我们的这次利用缓存进行加载有这样几个特点: 1、初始化的时候加载 2、滑动的时候才加载 3、加载的内容暂存缓存中 4、只加载显示的区域
篇6:Android 图像异步加载之AndroidUniversalImageLoader
项目地址:github.com/nostra13/Android-Universal-Image-Loader UIL(Universal-Image-Loader)异步图像加载、缓存和显示.这个图片异步加载并缓存的类已经被很多开发者所使用,是最常用的几个开源库之一,主流的应用,随便反编译几个火的项目,都可以见到它的身影, 同类类库(Picasso),尽管Picasso拥有更好的API,但其缺乏自定义。而使用UIL构建器几乎可以配置所有(其中最重要的就是在抓取和缓存大型图片时,Picasso会失败)。
特点: 多线程加载图像Multithread image loading (async or sync)宽泛的自定义配置Wide customization of ImageLoader's configuration (thread executors, downloader, decoder, memory and disk cache, display image options, etc.)Many customization options for every display image call (stub images, caching switch, decoding options, Bitmap processing and displaying, etc.)图像缓存Image caching in memory and/or on disk (device's file system or SD card)加载过程监听Listening loading process (including downloading progress) 简单描述一下这个项目的结构:每一个图片的加载和显示任务都运行在独立的线程中,除非这个图片缓存在内存中,这种情况下图片会立即显示。如果需要的图片缓存在本地,他们会开启一个独立的线程队列。如果在缓存中没有正确的图片,任务线程会从线程池中获取,因此,快速显示缓存图片时不会有明显的障碍。
由于源码中不管是loadImageSync还是loadImage最后都会通过displayImage来加载。那我们看看其流程:






