本文通过AyncTask异步加载网络图片
参考:
http://blog.youkuaiyun.com/xiaanming/article/details/9825113
1. ListView异步访问网络图片
1.通过Theard加载
通过Url获得位图
public Bitmap getBitmapFromurl(String urlString) {
Bitmap bitmap = null;
BufferedInputStream is = null;
URLConnection connection;
try {
URL url = new URL(urlString);//把一个string转化为Url
connection = (URLConnection) url.openConnection();//通过url开启一个connection
is = new BufferedInputStream(connection.getInputStream());
bitmap = BitmapFactory.decodeStream(is);//将isbuffer流数据转化为bitmap
is.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
return bitmap;
}
通过Thread异步加载位图
public void showImage(ImageView imageView, final String url) {
new Thread() {
@Override
public void run() {
super.run();
Bitmap bitmap = getBitmapFromurl(url);
Message message = Message.obtain();
message.obj = bitmap;
mHandler.sendMessage(message);
}
}.start();
}
通过Header处理,在主线程刷新UI
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (mImageView.getTag().equals(url)) {//通过Tag防止图片错位
mImageView.setImageBitmap((Bitmap) msg.obj);
}
}
};
2.通过AsyncTask加载
public void showImageByAsyncTask(ImageView imageView, String url) {
Bitmap bitmap = getBitmapFromCache(url);//从缓存中读取位图
if (bitmap == null) {
new NewsAsyncTask(url).execute(url);//网络加载图片
//imageView.setImageResource(R.drawable.ic_launcher);//加载默认图片
} else {
imageView.setImageBitmap(bitmap);
}
}
private class NewsAsyncTask extends AsyncTask<String, Void, Bitmap> {
private String mUrl;
public NewsAsyncTask(String url) {
mUrl = url;
}
@Override
protected Bitmap doInBackground(String... params) {
mUrl = params[0];
Bitmap bitmap = getBitmapFromurl(mUrl);
if (bitmap != null) {
addBitmapToCache(mUrl, bitmap);//将bitmap添加进缓存
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
ImageView imageView = (ImageView) mListView.findViewWithTag(mUrl);
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
mTasks.remove(this);
}
}
2. ListView异步加载网络图片的问题及其优化
1. 加载网络图片错位问题:
通过文艺方法重写listview的getView方法,因为listview缓存机制的存在,缓存池中始终保持三个Item布局,并在加载下一个时用到前面回收的Item,前面的Item以前加载的布局会在后面布局中先加载,然后通过访问网络重新刷新,因此会有图片错位的问题。
通过为加载的网络图片设置Tag的方式解决。在为Item设置图片是先判断Tag是否正确,正确才进行加载。
2. 图片缓存机制
为了使加载过得图片不再重新加载,引进缓存机制来优化listview,这里使用的是LrucaChe
1. 定义
public LruCache<String, Bitmap> myLruCache;//定义一个LruCache泛型
2. 在构造方法中初始化它
// 获取运行时最大缓存
int maxMemory = (int) Runtime.getRuntime().maxMemory();
// 设置LruCache可用的最大缓存
int cacheSize = maxMemory / 5;
myLruCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String url, Bitmap bitmap) {
// 重写此方法用来衡量每张图片的大小,默认返回图片的数量
return bitmap.getByteCount();
}
};
3. 添加图片到缓存中
public void addBitmapToCache(String url, Bitmap bitmap) {
if (getBitmapFromCache(url) == null) {
myLruCache.put(url, bitmap);
}
}
4.从缓存中获取图片
public Bitmap getBitmapFromCache(String url) {
return myLruCache.get(url);
}
3. 滑动卡顿问题
在滑动时系统不停的加载网络图片然后刷新Item,频繁刷新UI容易使系统卡顿。
在滑动时停止一切数据加载任务,当滑动停止后再次加载当前页的数据
- Apater添加OnScrollListener接口
- 注册接口
- 在onScroll函数中获取当前页的Item的开始项与结束项,并判断如果是第一次启动则手动加载
- onScrollStateChanged函数中判断当前状态:滑动状态时停止加载图片线程,停止状态时启动加载图片线程
代码ListAdapter中:
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_TOUCH_SCROLL) {
// 停止加载图片
mImageload.cancelload();
} else if (scrollState == SCROLL_STATE_IDLE) {
// 开始加载图片
mImageload.loadImages(mStart, mEnd);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
mStart = firstVisibleItem;
mEnd = firstVisibleItem + visibleItemCount;
if (mFirst && visibleItemCount > 0) {
mImageload.loadImages(mStart, mEnd);
mFirst = false;
}
}
细节处理:
1. 定义String数组用来管理当前页面的URL,在loadImages中初始化它
public void loadImages(int start, int end) {
for (int i = start; i < end; i++) {
final String url = ListAdapter.URLS[i];
Bitmap bitmap = getBitmapFromCache(url);
if (bitmap == null) {
NewsAsyncTask task = new NewsAsyncTask(url);
task.execute(url);
mTasks.add(task);//将task加入集合,便于管理
} else {
ImageView imageView = (ImageView) mListView
.findViewWithTag(url);
imageView.setImageBitmap(bitmap);
}
}
}
定义一个集合,用于管理NewsAyncTask
private Set mTasks;
自定义关闭AyncTask函数
public void cancelload() { if (mTasks != null) { for (NewsAsyncTask task : mTasks) { task.cancel(false); } } }