发一个异步图片加载控件。网上也有大把的异步网络加载图片的控件,但是有一个问题,异步加载会造成列表中的图片混乱,因为列表的每一项的View都可能被重用,异步加载的时候多个异步线程引用到了同一个View造成图片加载混乱。该控件解决这个问题:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* 异步图片控件
* 使用:new AsyncImageView().asyncLoadBitmapFromUrl("http://xxxx","缓存路径"){
*
* @author gaoomei@gmail.com
* @site http://obatu.sinaapp.com
* @version 1.0
* @2011-12-3
*/
public class AsyncImageView extends ImageView {
/**
* 异步task加载器
*/
private AsyncLoadImage mAsyncLoad;
/**
* 下载回来的图片缓存存活时间,单位:秒(s),默认30分钟
*/
private long mCacheLiveTime = 1800;
public AsyncImageView(Context context) {
super(context);
}
public AsyncImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AsyncImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
*
*/
@Override
public void setImageDrawable(Drawable drawable) {
if (mAsyncLoad != null) {
mAsyncLoad.cancel(true);
mAsyncLoad = null;
}
super.setImageDrawable(drawable);
}
/**
* 重写下面几个设置图片资源的方法,目地是取消网络加载
*/
@Override
public void setImageResource(int resId) {
cancelLoad();
super.setImageResource(resId);
}
@Override
public void setImageURI(Uri uri) {
cancelLoad();
super.setImageURI(uri);
}
@Override
public void setImageBitmap(Bitmap bitmap) {
cancelLoad();
super.setImageBitmap(bitmap);
}
/**
* 取消正在进行的异步task
*/
public void cancelLoad() {
if (mAsyncLoad != null) {
mAsyncLoad.cancel(true);
mAsyncLoad = null;
}
}
/**
* 设置图片存活时间
*
* @param second
* 存活时间,单位【秒】,如果等于0或null,则不缓存
*/
public void setCacheLiveTime(long second) {
if (second == 0) {
this.mCacheLiveTime = 0;
} else if (second >= 0) {
this.mCacheLiveTime = second * 1000;
}
}
/**
* 从网络异步加载
*
* @param url
* @param saveFileName
*/
public void asyncLoadBitmapFromUrl(String url, String saveFileName) {
if (mAsyncLoad != null) {
mAsyncLoad.cancel(true);
}
// AsyncTask不可重用,所以每次重新实例
mAsyncLoad = new AsyncLoadImage();
mAsyncLoad.execute(url, saveFileName);
}
/**
* 异步加载器
*/
private class AsyncLoadImage extends AsyncTask<String, Integer, Bitmap> {
/**
* 是否取消
*/
private boolean isCancel = false;
@Override
protected Bitmap doInBackground(String... params) {
if (isCancel) {
return null;
}
String url = params[0];
String fileName = params[1];
try {
return getBitmap(url, fileName);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onCancelled() {
System.out.println("async load imgae cancel");
isCancel = true;
}
@Override
protected void onPostExecute(Bitmap result) {
if (!isCancel && result != null) {
AsyncImageView.this.setImageBitmap(result);
}
}
}
/**
* 下载图片
*
* @param urlString
* url下载地址
* @param fileName
* 缓存文件路径
* @throws IOException
*/
private Bitmap getBitmap(String urlString, String fileName)
throws IOException {
if (fileName == null || fileName.trim().isEmpty()) {
InputStream input = getBitmapInputStreamFromUrl(urlString);
return BitmapFactory.decodeStream(input);
}
File file = new File(fileName);
if (!file.isFile()
|| (mCacheLiveTime > 0 && (System.currentTimeMillis()
- file.lastModified() > mCacheLiveTime))) {
InputStream input = getBitmapInputStreamFromUrl(urlString);
file = saveImage(input, fileName);
// 如果文件结构创建失败,则直接从输入流解码图片
if (file == null || !file.exists() || !file.canWrite()
|| !file.canRead()) {
return BitmapFactory.decodeStream(input);
}
}
return BitmapFactory.decodeFile(file.getAbsolutePath());
}
/**
* 下载图片,输入InputStream
*
* @param urlString
* @return
* @throws IOException
*/
private InputStream getBitmapInputStreamFromUrl(String urlString)
throws IOException {
URL url = new URL(urlString);
URLConnection connection = url.openConnection();
connection.setConnectTimeout(25000);
connection.setReadTimeout(90000);
return connection.getInputStream();
}
/**
* 从输入流保存图片到文件系统
*
* @param fileName
* @param input
* @return
*/
private File saveImage(InputStream input, String fileName) {
if (fileName.trim().isEmpty() || input == null) {
return null;
}
File file = new File(fileName);
OutputStream output = null;
try {
file.getParentFile().mkdirs();
if (file.exists() && file.isFile()) {
file.delete();
}
if (!file.createNewFile()) {
return null;
}
output = new FileOutputStream(file);
byte[] buffer = new byte[4 * 1024];
do {
// 循环读取
int numread = input.read(buffer);
if (numread == -1) {
break;
}
output.write(buffer, 0, numread);
} while (true);
output.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return file;
}
}
来自:
obatu
分享到:
相关推荐
* 问题分析:我们在使用AsyncTask异步下载图片的时候,经常会用到convertView的重用,一般情况下,滑动后第一个可见的元素(我们给它命个名,称为A1)和 * listview的第一个元素(A)是公用一个convertView的...
为便于学习自定义的Adapter,本案例的界面未进行美化,功能已经实现,对于其中的getView(int position,View view ,ViewGroup vg)做了数据的填充操作。本案例功能及其简单,只涉及ListView中自定义适配器,没有对...
ListView中getView重用好多次,有头像的布局
写在前面的话: 看到标题这么长可能大家有点抓狂了,...我们自己定义了一个adapter并且通过getview方法对每一个条目进行了编辑和排版。然后最后将我们自定义的Adapter放入到了我们的ListView中以实现展示了这种效果下面
android自定义接口,然后在activity中实现点击监听,调用getView解决滑动错位的问题,
需要注意的是第三点,在重写getView方法时,不要判断convertView == null,如果判断convertView == null再实例化相关的控件,则刷新的是局部控件(这个尚需要观点有待论证)。 以下的程序代码就是围绕以上三点编写的...
今天在写一个GridView的BaseAdapter时发现,Adapter的getview方法在position为0的时候会连续调用好几次。 我们知道谷歌时是做过优化的,让view有个缓存,我怀疑是因为做缓存的原因才让position连续调用 log如图 可见...
异步创建View这种操作一般情况下是用不...以往的我们使用一个Listview一般都是为了展示一类布局相同的信息,这种情况下,我们可以通过adapter的getView()方法中的convertView来实现View的复用,使View不用反复创建。
Adapter类的定义: Adapter对象是AdapterView和底层数据见的桥梁。Adapter用于访问数据项,并且负责为数据项生成视图 ...运行机制简单说就是当getView()方法被调用是,如果convertView参数不为null,就使用co
以前倒是没有注意listview的getView会重复执行多次,这次因为布局比较复杂,所以在测试的时候去断点跟踪,发现同一条数据不断的重复执行。觉得很奇怪,于是上网搜索了一下。网上的解释基本一致,就是ListView布局时...
最近写Adapter写得多了,慢慢就熟悉了。 用ViewHolder,主要是进行一些性能优化,减少一些不必要的重复操作。(WXD同学教我的。) 具体不分析了,直接上一份代码吧: public class MarkerItemAdapter extends ...
在平常的开发过程中,我们的ListView可能不只是简单的显示下文本或者按钮,更多的是显示复杂的布局,这样的话,我们就得自己写布局和自定义adapter了,一般是继承于BaseAdapter,示例代码见下方。写ListView的点击...
应用程序需要自定义ListView中各行的外观。 创建一个自定义的XML布局,将其传递给某个常见的适配器,或者扩展你自己的适配器,然后用自定义的状态Drawable覆盖背景和选中状态下的行。
Adapter的作用就是ListView界面与数据之间的桥梁,当列表里的每一项显示到页面时,都会调用Adapter的getView方法返回一个View。想过没有? 在我们的列表有1000000项时会是什么样的?是不是会占用极大的系统资源? ...
Adapter的一种写法 package com.xxkjx.jiusanqi; import java.util.List; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; ...
主要分析Android中Listview滚动过程造成的图片显示重复、错乱、闪烁的原因及解决方法,...b、获取滑入屏幕的行item之前会先判断缓存中是否有可用的item,如果有,作为convertview参数传递给adapter的getview。 这样的
1.在adapter 的 getview方法里面启动加载图片的thread,如果listview在滑动则wait 2.监听listview滑动停止事件,获得listview显示的item的最上面和最下面的序号,并唤醒所有加载图片的thread,判断加载图片的序号...
写项目也有一段时间了,每次写ListView或者是GridView时,只要item内容不同,就要写不同的自定义adapter,感觉很麻烦,其实这些代码都可以抽出来,我们需要做的只是改写getView方法和ViewHolder,那下面我们就开始吧...
第一种优化就是重用convertView,这也是最简单的一种优化方式,就是在Adapter类的getView方法中通过判断convertView是否为null,是的话就需要在创建一个视图出来,然后给视图设置数据,最后将这个视图返回给底层,...
一个通用的适配器类,抽象了adapter的常用方法,只需要继承后重写getview()这个方法就可以了,方便适用 public abstract View getView(int position, View convertview, ViewGroup group);