前言:本以为异步加载挺简单,因为网上代码多,但真想要做好,还真不那么简单,从看代码到弄懂再到自己写,实在是有太多的东西需要学了,用了两天的时间,终于弄出来了,因为用到回调函数,所以理解起来可能难度有点大,讲起来也不太好讲,我尽力讲的明白些,其实还是要多看代码,自己摸索摸索,动手写写就什么都理解了。这篇我们只讲怎样实现异步加载,对于滑动时停止加载的事下篇再讲。
实现效果:
1、异步加载图片,在加载图片时,先加载一个默认的图片,然后在后台加载图片,加载完成后显示出来;
2、当用户在滑动时,停止加载图片的线程,当停止滑动时,看哪几个ITEM在显示屏内,只加载这几个,其它线程保持阻止;(下篇再讲)
效果图:
刚开始加载时 向下划动(新划出来的是空白块) 停划,加载完成
一、XML
1、main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <ListView android:id="@+id/list"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent" />
- </LinearLayout>
2、列表子项XML(book_item_adapter.xml)
- <?xml version="1.0" encoding="UTF-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="70.0dip"
- android:background="@drawable/item"
- android:drawingCacheQuality="high"
- android:minHeight="70.0dip"
- android:orientation="horizontal" >
- <ImageView
- android:id="@+id/sItemIcon"
- android:layout_width="42.0dip"
- android:layout_height="54.0dip"
- android:layout_margin="10.0dip"
- android:background="@drawable/rc_item_bg"
- android:padding="2.0dip"
- android:scaleType="fitXY" />
- <TextView
- android:text="斗破苍穹"
- android:id="@+id/sItemTitle"
- android:layout_width="fill_parent"
- android:layout_height="30.0dip"
- android:layout_alignTop="@+id/sItemIcon"
- android:layout_toRightOf="@+id/sItemIcon"
- android:gravity="center_vertical"
- android:singleLine="true"
- android:textColor="#ffffff"
- android:textSize="18.0sp" />
- </RelativeLayout>
二、JAVA代码
1、主页面代码(AsyncListImage.java)
- package cn.wangmeng.test;
- import java.util.ArrayList;
- import java.util.List;
- import android.app.Activity;
- import android.os.Bundle;
- import android.widget.ListView;
- public class AsyncListImage extends Activity {
- private ListView list;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- list=(ListView)findViewById(R.id.list);
- List<ImageAndText> dataArray=new ArrayList<ImageAndText>();
- for (int i = 0; i < 100; i++) {
- ImageAndText test=new ImageAndText("http://www.wangmeng.cn/images/logo.gif", "test");
- ImageAndText test1=new ImageAndText("http://www.pfwx.com/files/article/image/0/54/54s.jpg", "test1");
- ImageAndText test2=new ImageAndText("http://www.pfwx.com/files/article/image/0/4/4s.jpg","test2");
- ImageAndText test3=new ImageAndText("http://www.pfwx.com/files/article/image/9/9760/9760s.jpg","test3");
- ImageAndText test4=new ImageAndText("http://www.pfwx.com/files/article/image/3/3382/3382s.jpg","test4");
- ImageAndText test5=new ImageAndText("http://www.pfwx.com/files/article/image/3/3237/3237s.jpg","test5");
- dataArray.add(test);
- dataArray.add(test1);
- dataArray.add(test2);
- dataArray.add(test3);
- dataArray.add(test4);
- dataArray.add(test5);
- }
- ImageAndTextListAdapter adapter=new ImageAndTextListAdapter(this, dataArray, list);
- list.setAdapter(adapter);
- }
- }
2、ImageAndText.java
- package cn.wangmeng.test;
- public class ImageAndText {
- private String imageUrl;
- private String text;
- public ImageAndText(String imageUrl, String text) {
- this.imageUrl = imageUrl;
- this.text = text;
- }
- public String getImageUrl() {
- return imageUrl;
- }
- public String getText() {
- return text;
- }
- }
1、ImageAndText类是用来存储要与XML绑定的图片地址和名字地址的。
2、将所有的地址都放在一个List里面(dataArray),然后将其传入ImageAndTextListAdapter()函数中;可见这个ImageAndTextListAdapter()函数是根据传进去的dataArray生成对应的Adapter的
3、然后将ImageAndTextListAdapter()返回的Adapter与listView绑定
3、ImageAndTextListAdapter.java
这是重写于baseAdapter的类,由于重写于baseAdapter,所以有几个必须重写的函数,getCount()、getItem()、getItemId()、getView(),我们先把总体代码写出来,只讲一个getView()函数,其实函数就不讲了,先着重说下getView()函数在什么时候被系统调用:
getView()函数在什么时候被系统调用:
注意一点是Android系统在显示列表时,并不是把所有代表都显示出来,让你随便划,划到哪是哪;而是根据当前的在划到的ITEM,调用当前ITEM的getView()来显示它。
全部代码:
- package cn.wangmeng.test;
- import java.util.ArrayList;
- import java.util.List;
- import cn.wangmeng.test.AsyncImageLoader.ImageCallback;
- import android.app.Activity;
- import android.graphics.drawable.Drawable;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.ArrayAdapter;
- import android.widget.BaseAdapter;
- import android.widget.ImageView;
- import android.widget.ListView;
- import android.widget.TextView;
- public class ImageAndTextListAdapter extends BaseAdapter {
- private LayoutInflater inflater;
- private ListView listView;
- private AsyncImageLoader asyncImageLoader;
- private List<ImageAndText> dataArray=new ArrayList<ImageAndText>();
- public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) {
- this.listView = listView;
- asyncImageLoader = new AsyncImageLoader();
- inflater = activity.getLayoutInflater();
- dataArray=imageAndTexts;
- }
- @Override
- public int getCount() {
- // TODO Auto-generated method stub
- return dataArray.size();
- }
- @Override
- public Object getItem(int position) {
- // TODO Auto-generated method stub
- if(position >= getCount()){
- return null;
- }
- return dataArray.get(position);
- }
- @Override
- public long getItemId(int position) {
- // TODO Auto-generated method stub
- return position;
- }
- //不需要ViewHolder版,直接将ImageAndText与XML资源关联起来
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = inflater.inflate(R.layout.book_item_adapter, null);
- }
- convertView.setTag(position);
- ImageAndText imageAndText = (ImageAndText) getItem(position);
- String imageUrl = imageAndText.getImageUrl();
- TextView textView = (TextView) convertView.findViewById(R.id.sItemTitle);
- // 将XML视图项与用户输入的URL和文本在绑定
- textView.setText(imageAndText.getText());//加载TEXT
- ImageView iv = (ImageView) convertView.findViewById(R.id.sItemIcon);
- iv.setBackgroundResource(R.drawable.rc_item_bg);//在初始化时,先把背景图片设置成默认背景,
- //否则在下拉时会随机匹配背景,不美观
- asyncImageLoader.loadDrawable(position,imageUrl, new ImageCallback() {
- @Override
- public void onImageLoad(Integer pos, Drawable drawable) {
- View view = listView.findViewWithTag(pos);
- if(view != null){
- ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
- iv.setBackgroundDrawable(drawable);
- }
- }
- //加载不成功的图片处理
- @Override
- public void onError(Integer pos) {
- View view = listView.findViewWithTag(pos);
- if(view != null){
- ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
- iv.setBackgroundResource(R.drawable.rc_item_bg);
- }
- }
- });
- return convertView;
- }
- }
1、看这段:
- if (convertView == null) {
- convertView = inflater.inflate(R.layout.book_item_adapter, null);
- }
- convertView.setTag(position);
- ImageAndText imageAndText = (ImageAndText) getItem(position);
- String imageUrl = imageAndText.getImageUrl();
- TextView textView = (TextView) convertView.findViewById(R.id.sItemTitle);
- // 将XML视图项与用户输入的URL和文本在绑定
- textView.setText(imageAndText.getText());//加载TEXT
- ImageView iv = (ImageView) convertView.findViewById(R.id.sItemIcon);
- iv.setBackgroundResource(R.drawable.rc_item_bg);
- asyncImageLoader.loadDrawable(position,imageUrl, new ImageCallback() {
- @Override
- public void onImageLoad(Integer pos, Drawable drawable) {
- View view = listView.findViewWithTag(pos);
- if(view != null){
- ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
- iv.setBackgroundDrawable(drawable);
- }
- }
- //加载不成功的图片处理
- @Override
- public void onError(Integer pos) {
- View view = listView.findViewWithTag(pos);
- if(view != null){
- ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
- iv.setBackgroundResource(R.drawable.rc_item_bg);
- }
- }
- });
(1)、传进去的参数,当前项的位置(position),当前图片的URL(imageUrl),一个名称为ImageCallback()接口函数;
(2)、ImageCallback()接口函数里的两个被重写的函数onImageLoad()和onError()
3、AsyncImageLoader.java
从上面的讲解也应该能猜到这个类,主要的功能就是加载图片,然后成功后更新UI;
先看全部代码,然后再逐步讲
- package cn.wangmeng.test;
- import java.io.IOException;
- import java.io.InputStream;
- import java.lang.ref.SoftReference;
- import java.net.URL;
- import java.util.HashMap;
- import android.graphics.drawable.Drawable;
- import android.os.Handler;
- public class AsyncImageLoader {
- final Handler handler = new Handler();
- private HashMap<String, SoftReference<Drawable>> imageCache;
- public AsyncImageLoader() {
- imageCache = new HashMap<String, SoftReference<Drawable>>();//图片缓存
- }
- // 回调函数
- public interface ImageCallback {
- public void onImageLoad(Integer t, Drawable drawable);
- public void onError(Integer t);
- }
- public Drawable loadDrawable(final Integer pos, final String imageUrl,
- final ImageCallback imageCallback) {
- new Thread() {
- @Override
- public void run() {
- LoadImg(pos, imageUrl, imageCallback);
- }
- }.start();
- return null;
- }// loadDrawable---end
- public void LoadImg(final Integer pos, final String imageUrl,
- final ImageCallback imageCallback) {
- // 首先判断是否在缓存中
- // 但有个问题是:ImageCache可能会越来越大,以至用户内存用光,所以要用SoftReference(弱引用)来实现
- if (imageCache.containsKey(imageUrl)) {
- SoftReference<Drawable> softReference = imageCache.get(imageUrl);
- final Drawable drawable = softReference.get();
- if (drawable != null) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- imageCallback.onImageLoad(pos, drawable);
- }
- });
- return;
- }
- }
- // 尝试从URL中加载
- try {
- final Drawable drawable = loadImageFromUrl(imageUrl);
- if (drawable != null) {
- imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
- }
- handler.post(new Runnable() {
- @Override
- public void run() {
- imageCallback.onImageLoad(pos, drawable);
- }
- });
- } catch (IOException e) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- imageCallback.onError(pos);
- }
- });
- e.printStackTrace();
- }
- }
- // 根据URL加载图片,如果出现错误throws IOException式的错误,以便在LoadImg中捕获,执行OnError()函数
- public static Drawable loadImageFromUrl(String url) throws IOException {
- URL m;
- InputStream i = null;
- m = new URL(url);
- i = (InputStream) m.getContent();
- Drawable d = Drawable.createFromStream(i, "src");
- return d;
- }
- }
1、先看这段代码
- // 回调函数
- public interface ImageCallback {
- public void onImageLoad(Integer t, Drawable drawable);
- public void onError(Integer t);
- }
- public Drawable loadDrawable(final Integer pos, final String imageUrl,
- final ImageCallback imageCallback) {
- new Thread() {
- @Override
- public void run() {
- LoadImg(pos, imageUrl, imageCallback);
- }
- }.start();
- return null;
- }// loadDrawable---end
(2)上面也看出了ImageCallback是一个接口,而里面的两个函数onImageLoad()和onError()在这里是没有具体实现的,那在哪里实现呢,当然是我们上面的ImageAndTextListAdapter.java里面了,等下我们具体会再讲。
再往下看
- // 根据URL加载图片,如果出现错误throws IOException式的错误,以便在LoadImg中捕获,执行OnError()函数
- public static Drawable loadImageFromUrl(String url) throws IOException {
- URL m;
- InputStream i = null;
- m = new URL(url);
- i = (InputStream) m.getContent();
- Drawable d = Drawable.createFromStream(i, "src");
- return d;
- }
- public void LoadImg(final Integer pos, final String imageUrl,
- final ImageCallback imageCallback) {
- // 首先判断是否在缓存中
- // 但有个问题是:ImageCache可能会越来越大,以至用户内存用光,所以要用SoftReference(弱引用)来实现
- if (imageCache.containsKey(imageUrl)) {
- SoftReference<Drawable> softReference = imageCache.get(imageUrl);
- final Drawable drawable = softReference.get();
- if (drawable != null) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- imageCallback.onImageLoad(pos, drawable);
- }
- });
- return;
- }
- }
- // 尝试从URL中加载
- try {
- final Drawable drawable = loadImageFromUrl(imageUrl);
- if (drawable != null) {
- imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
- }
- handler.post(new Runnable() {
- @Override
- public void run() {
- imageCallback.onImageLoad(pos, drawable);
- }
- });
- } catch (IOException e) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- imageCallback.onError(pos);
- }
- });
- e.printStackTrace();
- }
- }
(2)、对于LoadImg()我们再拆一下,先看如何在缓存中加载
- if (imageCache.containsKey(imageUrl)) {
- SoftReference<Drawable> softReference = imageCache.get(imageUrl);
- final Drawable drawable = softReference.get();
- if (drawable != null) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- imageCallback.onImageLoad(pos, drawable);
- }
- });
- return;
- }
- }
1、在这里就已经得到了图像
- SoftReference<Drawable> softReference = imageCache.get(imageUrl);
- final Drawable drawable = softReference.get();
- if (drawable != null) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- imageCallback.onImageLoad(pos, drawable);
- }
- });
- return;
- }
- asyncImageLoader.loadDrawable(position,imageUrl, new ImageCallback() {
- @Override
- public void onImageLoad(Integer pos, Drawable drawable) {
- View view = listView.findViewWithTag(pos);
- if(view != null){
- ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
- iv.setBackgroundDrawable(drawable);
- }
- }
- });
OK,就到这吧,OnError()的原理一样,只不过是对程序没有加载到图片时应该怎么处理,其实就是当没有加载到图片时就是默认图片代替。
下面给出源码:http://download.youkuaiyun.com/detail/harvic880925/6802241(不要分,仅供分享)