Android异步加载学习笔记之四:利用缓存优化网络加载图片及ListView加载优化

如果不做任何处理,直接用网络加载图片在网速快的情况下可能没什么不好的感觉,但是如果使用移动流量或是网络不好的时候,问题就来了,要么用户会抱怨流量使用太多,要么抱怨图片加载太慢,如论从哪个角度出发,都不是好的体验!要提高用户体验,我们就要使用缓存。Android中数据缓存的方式有很多,相关介绍的文章也比较多,比如http://blog.csdn.net/dahuaishu2010_/article/details/17093139http://www.jb51.net/article/38162.htm等。今天学习是是Lru缓存。

Lru(Least Recently Used)近期最少使用算法,即是在一定条件下LRU缓存是把最近最少使用的数据移除,让给最新读取的数据。而往往最常读取的,也是读取次数最多的,所以,利用LRU缓存,我们能够提高应用的效率及用户体验度。Andorid本身提供了LruCache类来实现这个缓存算法 。

在ImageLoader中利用LruCache缓存:

public class ImageLoader {

private LruCache<String, Bitmap> mCaches;// 创建LruCache对象

private ImageView mImageView;

private ListView listView;

private Set<ImageAsyncTask> mTask;

@SuppressLint("NewApi")

public ImageLoader(ListView listView) {

this.listView = listView;

mTask = new HashSet<ImageAsyncTask>();

int maxMemory = (int) Runtime.getRuntime().maxMemory();// 获取最大可用内存

int cacheSize = maxMemory / 8;// 设置缓存数据的最大占用内存量为最大值1/8

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

@Override

protected int sizeOf(String key, Bitmap value) {

return value.getByteCount();// 每次存入缓存的时候调用,返回bitmap的大小

}

};

}

@SuppressLint("NewApi")

/**

* 增加缓存数据,增加前判断数据是否存在

* @description:

* @author ldm

* @date 2015-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<String, Void, Bitmap> {

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<DataBean> 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<DataBean> list, ListView listView) {

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在流动状态变化时调用

*/

@Override

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;

}

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-30 10:08:12

Android异步加载学习笔记之四:利用缓存优化网络加载图片及ListView加载优化的相关文章

学习笔记:利用GDI+生成简单的验证码图片

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 学习笔记:利用GDI+生成简单的验证码图片 1 /// <summary> 2 /// 单击图片时切换图片 3 /// </summary> 4 /// <param name="sender">&

加壳学习笔记(三)-简单的脱壳思路&amp;调试思路

首先一些windows的常用API: GetWindowTextA:以ASCII的形式的输入框 GetWindowTextW:以Unicaode宽字符的输入框 GetDlgItemTextA:以ASCII的形式的输入框 GetDlgItemTextW:以Unicaode宽字符的输入框 这些函数在使用的时候会有些参数提前入栈,如这函数要求的参数是字符串数目.还有大小写啦之类的东西,这些东西是要在调用该函数之前入栈,也就是依次push,就是说一般前面几个push接着一个call,那前面的push可能

Android(java)学习笔记160:Framework运行环境之启动Zygote

前面Android(java)学习笔记159提到Dalvik虚拟机启动初始化过程,就下来就是启动zygote进程: zygote进程是所有APK应用进程的父进程:每当执行一个Android应用程序,Zygote就会孵化一个子线程去执行该应用程序(系统内部执行dvz指令完成的)  Å特别注意:系统提供了一个app_process进程,它会自动启动ZygoteInit.java和SystemServer.java这两个类,app_process进程本质上是使用dalvikvm启动ZygoteInit

MyBatis association的两种形式——MyBatis学习笔记之四

一.嵌套的resultMap 这 种方法本质上就是上篇博文介绍的方法,只是把教师实体映射从association元素中提取出来,用一个resultMap元素表示.然后 association元素再引用这个resultMap元素.修改上篇博文示例的StudentMapper.xml如下: <?xml version="1.0" encoding="utf8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org

马哥Linux学习笔记之四——DNS

1.BIND:Berkeley Internet Name Domain DNS:Domian Name Service 域名解析 2. Http 3.PAM 插入式认证模块 4.SMTP/POP3/IMAP4:Mail Server 5.域名 www.baidu.com这是一个主机名(FQDN,Full Qualified Domain Name,完全限定域名),com是一个域名,baidu.com也是一个域名,域名是好多主机的集合. 域名解析起后面有一个数据库,解析就是一个查询的过程.域名解

Android(java)学习笔记204:自定义SmartImageView(继承自ImageView,扩展功能为自动获取网络路径图片)

1.有时候Android系统配置的UI控件,不能满足我们的需求,Android开发做到了一定程度,多少都会用到自定义控件,一方面是更加灵活,另一方面在大数据量的情况下自定义控件的效率比写布局文件更高. 2.下面我们是自定义一个SmartImageView继承自ImageView,扩展了ImageView的功能:     步骤: • 新建一个SmartImageView类,让继承自ImageView(放置特定的包下): • 实现SmartImageView类下的构造方法,最好全部实现,这个不容易出

加壳学习笔记(一)-基础知识

1.预备知识 1.关于栈,在windows里面的堆栈其实很简单,当学了才知道哈,呵呵,第一要记住的是windows里面的栈是向低地址生长的(extended,延伸,呵呵,顺便丰富下英语的单词量,确实是少的可怜),你可以这样认为,栈就像是一个倒立的箱子,箱子的口子是向下的,底是向上的,这里就表明了系统栈的分布也是延伸方向是由高地址向低地址extended,在最初的空栈阶段,栈顶(extended stack pointer,简称是esp)在栈底的低一个位置,呵呵,其实很好理解,就是说最初的箱子是空

Android(java)学习笔记207:开源项目使用之gif view

1. 由于android没有自带的gif动画,我在Android(java)学习笔记198:Android下的帧动画(Drawable Animation) 播客中提到可以使用AnimationView(帧动画)方法先将一个gif动画利用软件分割成若干静态图片,然后按照一定的时间间隔和播放顺序一帧一帧播放图片,从而给用户体验仿佛是动画gif播放的效果 2.其实网上的开源项目中有更为完善的gif动画播放的代码,下面以此为例进一步了解开源项目的使用: (1)在https://github.com/网

Android(java)学习笔记71:生产者和消费者之等待唤醒机制

首先我们根据梳理我们之前Android(java)学习笔记70中关于生产者和消费者程序思路: 下面我们就要重点介绍这个等待唤醒机制: 第一步:还是先通过代码体现出等待唤醒机制 package cn.itcast_05; /* * 分析: * 资源类:Student * 设置学生数据:SetThread(生产者) * 获取学生数据:GetThread(消费者) * 测试类:StudentDemo * * 问题1:按照思路写代码,发现数据每次都是:null---0 * 原因:我们在每个线程中都创建了