解决ListView异步加载图片错乱问题 .

发一个异步图片加载控件。网上也有大把的异步网络加载图片的控件,但是有一个问题,异步加载会造成列表中的图片混乱,因为列表的每一项的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 [email protected]

 * @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 {

        /**

         * 是否取消

         */

        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;

    }

}

 

你可能感兴趣的:(ListView)