您的位置:首页 > 其它

异步加载图片

2015-08-17 11:05 381 查看
实现效果:

1、异步加载图片,在加载图片时,先加载一个默认的图片,然后在后台加载图片,加载完成后显示出来;

2、当用户在滑动时,停止加载图片的线程,当停止滑动时,看哪几个ITEM在显示屏内,只加载这几个,其它线程保持阻止;(下篇再讲)

效果图:

刚开始加载时 向下划动(新划出来的是空白块) 停划,加载完成








一、XML


1、main.xml

[html] view
plaincopy





<?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)

[html] view
plaincopy





<?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)

[java] view
plaincopy





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

[java] view
plaincopy





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()来显示它。

全部代码:

[java] view
plaincopy





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;

}

}

我们着重看getView()函数

1、看这段:

[java] view
plaincopy





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);

这段代码没什么特别的就是将前面dataArray的信息与XML的元素项对应起来,并绑定,最关键的是下面这段,下面这个方法才是实现异步加载图片的关键:

[java] view
plaincopy





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);

}

}

});

这段代码的奇特之处在于,利用AsyncImageLoader类的实例(asyncImageLoader),调用方法loadDrawable()方法,就实现了加载后图像的绑定;好神奇,仔细看他是怎么做到的。这里先注意的有两点:

(1)、传进去的参数,当前项的位置(position),当前图片的URL(imageUrl),一个名称为ImageCallback()接口函数;

(2)、ImageCallback()接口函数里的两个被重写的函数onImageLoad()和onError()


3、AsyncImageLoader.java

从上面的讲解也应该能猜到这个类,主要的功能就是加载图片,然后成功后更新UI;

先看全部代码,然后再逐步讲

[java] view
plaincopy





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、先看这段代码

[java] view
plaincopy





// 回调函数

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

(1)首先注意,刚才我们调用的loadDrawable()函数,里面初始化并运行了一个线程,而这个线程的里面只有一个函数LoadImg(),对于这个函数下面我们具体讲,它的主要功能就是加载图片,然后更新UI

(2)上面也看出了ImageCallback是一个接口,而里面的两个函数onImageLoad()和onError()在这里是没有具体实现的,那在哪里实现呢,当然是我们上面的ImageAndTextListAdapter.java里面了,等下我们具体会再讲。

再往下看

[java] view
plaincopy





// 根据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();

}

}

(1)、loadImageFromUrl()函数,就是根据URL到网上加载图片,然后返回图片流Drawable类型变量

(2)、对于LoadImg()我们再拆一下,先看如何在缓存中加载

[java] view
plaincopy





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、在这里就已经得到了图像

[java] view
plaincopy





SoftReference<Drawable> softReference = imageCache.get(imageUrl);

final Drawable drawable = softReference.get();

2、得到图像之后就到了这段代码:

[java] view
plaincopy





if (drawable != null) {

handler.post(new Runnable() {

@Override

public void run() {

imageCallback.onImageLoad(pos, drawable);

}

});

return;

}

当我们得到图像之后,调用imageCallback.onImageLoad(pos, drawable);来更新UI,由于我们再回来看看ImageAndTextListAdapter.java中的代码

[java] view
plaincopy





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);

}

}

});

看到了吧,就是把得到的drawable与加载到UI中!!!!这就实现了回调

OK,就到这吧,OnError()的原理一样,只不过是对程序没有加载到图片时应该怎么处理,其实就是当没有加载到图片时就是默认图片代替。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: