您的位置:首页 > 其它

简单的ListView中item图片异步加载

2015-07-08 23:12 344 查看
前言:

在android开发当中,从目标地址获取图片往往都是采用异步加载的方法。当完全加载完图片后在进行显示,也有些是直接将加载的图片一点一点的显示出来。
这两个区别只是对流的处理不同而已。现在就讲讲当图片被完全获取到后在显示的方法。
一,效果图:

初始化: 获取后:





1.1,效果思路:
初始化的时候默认ImageView显示一张白色的图片,在加载完图片以后,用心的图片将白色图片给替换掉,就达到效果了。
二,代码实现:
主要类介绍:
AsyncImageLoadAdapter :ListView的自定义Adapter
AsyncLoad :图片异步加载类
MainActivity :主Activity。
相关的布局文件就不介绍了,在后面看就行了。
MainActivity:

public class MainActivity extends Activity {

private ListView listView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}

private void initView() {
listView = (ListView) findView(R.id.listView);
}

private void initData() {
List<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();
HashMap<String, Object> map1 = new HashMap<String, Object>();
map1.put("img",
"http://img5.imgtn.bdimg.com/it/u=747474479,3247936386&fm=21&gp=0.jpg");
map1.put("txt", "条目一");
HashMap<String, Object> map2 = new HashMap<String, Object>();
map2.put("img",
"http://pic.nipic.com/2007-12-22/2007122215556437_2.jpg");
map2.put("txt", "条目二");
HashMap<String, Object> map3 = new HashMap<String, Object>();
map3.put("img",
"http://img1.imgtn.bdimg.com/it/u=1774561363,2410491846&fm=21&gp=0.jpg");
map3.put("txt", "条目三");
HashMap<String, Object> map4 = new HashMap<String, Object>();
map4.put("img",
"http://img5.imgtn.bdimg.com/it/u=112049007,3368205326&fm=21&gp=0.jpg");
map4.put("txt", "条目四");
HashMap<String, Object> map5 = new HashMap<String, Object>();
map5.put("img",
"http://img3.imgtn.bdimg.com/it/u=2953608063,4260501712&fm=21&gp=0.jpg");
map5.put("txt", "条目五");
list.add(map1);
list.add(map2);
list.add(map3);
list.add(map4);
list.add(map5);
AsyncImageLoadAdapter adapter = new AsyncImageLoadAdapter(
MainActivity.this, list, listView);
listView.setAdapter(adapter);
}

private <T> T findView(int id) {
return (T) findViewById(id);
}

}


这个MainActivity挺简单的,就是初始化相关控件,然后给ListView附上值而已。

AsyncImageLoadAdapter :
  

public class AsyncImageLoadAdapter extends BaseAdapter {

private Context context;

private List<HashMap<String, Object>> listData;

private AsyncLoad asyncLoad;

private ListView listView;

public AsyncImageLoadAdapter(Context context1,
List<HashMap<String, Object>> listData1, ListView listView1) {
this.context = context1;
this.listData = listData1;
this.asyncLoad = AsyncLoad.instance();
this.listView = listView1;
}

@Override
public int getCount() {
return listData.size();
}

@Override
public Object getItem(int position) {
return listData.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(
R.layout.list_item, null);
}

convertView.setTag(position);
ImageView imageView = (ImageView) convertView
.findViewById(R.id.list_item_img);
imageView.setBackgroundResource(R.drawable.img_black);
TextView textView = (TextView) convertView
.findViewById(R.id.list_item_tv);
textView.setText("我是条目" + position);
HashMap<String, Object> item = listData.get(position);
String imageStr = (String) item.get("img");
asyncLoad.loadImage(position, imageStr, new ILoadListener() {

@SuppressLint("NewApi")
@Override
public void onSuccess(Integer pos, Drawable drawable) {
View view = listView.findViewWithTag(pos);

if (view != null) {
ImageView img = (ImageView) view
.findViewById(R.id.list_item_img);

img.setBackground(drawable);
}
}

@Override
public void onFail(String failStr) {
Toast.makeText(context, "错误信息是->" + failStr, Toast.LENGTH_SHORT)
.show();
}
});

return convertView;
}
}


这个Adapter中加载了一个list_item布局(adapter中未用ViewHolder,不要去纠结这个,加上也可),来初始化未加载图片的时候。主要要说的是这段代码

asyncLoad.loadImage(position, imageStr, new ILoadListener() {
@SuppressLint("NewApi")
@Override
public void onSuccess(Integer pos, Drawable drawable) {
View view = listView.findViewWithTag(pos);
if (view != null) {
ImageView img = (ImageView) view
.findViewById(R.id.list_item_img);
img.setBackground(drawable);
}
}
@Override
public void onFail(String failStr) {
Toast.makeText(context, "错误信息是->" + failStr, Toast.LENGTH_SHORT)
.show();
}
});


这段代码就进行了异步去加载图片。
思路是:先将ListView中的每个item设置一个Tag,便于后面找到对应的item中imageView进行图片更新。
然后利用图片加载类去网络获取图片,获取到图片后采用接口回调的方式传回图片进行ImageView更新(UI线程中
执行的)

  AsyncLoad:
[b]  [/b]

public class AsyncLoad {

private static AsyncLoad asyncLoad;
/**
* 图片缓存容器,采用软引用,当用户手机内存不够时候,系统自动回收其所占有的内存
*/
private HashMap<String, SoftReference<Drawable>> dataMap;
/**
* 用于在UI线程中进行UI更新
*/
private Handler handler = new Handler();

public synchronized static AsyncLoad instance() {

if (asyncLoad == null)
asyncLoad = new AsyncLoad();
return asyncLoad;

}

public AsyncLoad() {
dataMap = new HashMap<String, SoftReference<Drawable>>();
}

// 内部接口对图片获取的监听
interface ILoadListener {
/**
* 图片加载成功后
*
* @param pos
*            对listView中pos位置
* @param drawable
*            网络加载后获取到的图片
*/
public void onSuccess(Integer pos, Drawable drawable);

public void onFail(String failStr);

}

/**
* 开启线程对图片进行加载
*
* @param pos
*            listView的pos位置进行加载
* @param imageStr
*            图片地址
* @param listener
*            监听接口
*/

public void loadImage(final Integer pos, final String imageStr,
final ILoadListener listener) {

// 开启一个线程获取图片资源
new Thread(new Runnable() {

@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
load(pos, imageStr, listener);
}
}).start();

}

private void load(final Integer pos, final String imageStr,
final ILoadListener listener) {

if (dataMap.containsKey(imageStr)) {

SoftReference<Drawable> softReference = dataMap.get(imageStr);
final Drawable d = softReference.get();
if (d != null) {
handler.post(new Runnable() {

@Override
public void run() {

listener.onSuccess(pos, d);
}
});
}
return;

}

try {
final Drawable d = loadImgFromUrl(imageStr);
if (d != null) {
SoftReference<Drawable> soft = new SoftReference<Drawable>(d);
dataMap.put(imageStr, soft);
}
handler.post(new Runnable() {

@Override
public void run() {

listener.onSuccess(pos, d);

}
});

} catch (final IOException e) {
e.printStackTrace();
// 进行错误信息回报
handler.post(new Runnable() {

@Override
public void run() {

listener.onFail(e.getMessage());

}
});

}

}

/**
* 获取网路图片资源
*
* @param url
* @return
* @throws IOException
*/
private static Drawable loadImgFromUrl(String urlStr) throws IOException {
System.out.println("urlStr->" + urlStr);
URL url;
InputStream i = null;
url = new URL(urlStr);
i = (InputStream) url.getContent();
Drawable drawable = Drawable.createFromStream(i, "img");

return drawable;

}

}


要想更新界面上内容,就必须在UI线程中去更新,所以就采用handler.post方法,post里面Runnable中
run执行的代码其实是在UI线程中执行的,所以就符合android的规矩,才能进行更新

参考文章:http://blog.csdn.net/harvic880925/article/details/17766027#t7
源码下载:下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: