论坛首页 移动开发技术论坛

异步加载图片

浏览 13263 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-08-20  

前几天记得说要分享一下异步下载加载图片的经验,最近一直在研究Cocos2d,把这事耽误了。今天就写了写 

 

如果不怕图片那个内存溢出的bug的话。可以使用ListView,GridView等等,如果担心这个问题,可以使用ImageView

 

既然是异步加载,那就采用多线程下载吧。 这个例子里面也就用了一个线程池

 

1.

//初始化线程池

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 3,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());

 

2.

    //构建一个ListView

listView = (ListView) findViewById(R.id.listview);

 

3.

   //启动一个下载列表的线程

threadPool.execute(new LoadImagesListThread());

 

4.

        /**
	 * 下载图片列表的线程
	 * @author zhu
	 *
	 */
	class LoadImagesListThread extends Thread{
		@Override
		public void run() {

			//TODO 获取下载图片列表的
			datas = HttpUtils.LoadImagesList(); 

			if(datas != null && datas.size()>0){
				
				//通知显示列表
				handler.sendEmptyMessage(SHOW_IMAGES);
				
				//循环启动线程下载图片
				for (int i = 0; i < datas.size(); i++) {
					threadPool.execute(new LoadImageThread());
				}
			}else{
				//TODO 通知没有数据
				handler.sendEmptyMessage(NO_IMAGES);
			}
		}
		
	}

5.

下载图片的线程如下,很简单

	class LoadImageThread extends Thread{
		
		int position;
		
		public LoadImageThread(int position){
			this.position = position;
		}
		
		@Override
		public void run() {
			//TODO 下载图片。这个下载方法里面可以先判断是否本地缓存有,如果有,就读缓存。没有就下载,再写缓存
			datas.get(position).bitmap = HttpUtils.loadImage(datas.get(position).url);
			handler.sendEmptyMessage(SHOW_IMAGE);
		}
		
	}

6.

handler里面主要做些刷新的工作

	Handler handler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case SHOW_IMAGES:
				adapter = new MyAdapter();
				listView.setAdapter(adapter);
				break;
			case NO_IMAGES:
				Toast.makeText(MainActivity.this, "no images", Toast.LENGTH_LONG).show();
				break;
			case SHOW_IMAGE:
				adapter.notifyDataSetChanged();
				break;
			default:
				break;
			}
			
		};
	};
 

 

至此一个简单的异步加载图片的功能完成了。

 

图片太多。使用ListView,GridView的时候会报内存溢出的错误,我的经验是320x480大小的12张左右必报。坛子里也讨论了许久,没有结果,都是缩放图片或者避开这个大量图片的问题。我就采用的是避开大量图片的方法。过几天再写出来

 

 

 

   发表时间:2010-08-21  
不错  很简练  学习了  期待有更精彩的深入研究
0 请登录后投票
   发表时间:2010-08-24  
你是在哪讨论的?
0 请登录后投票
   发表时间:2010-08-24  
package com.zbkc.mamclient.ui.common;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
import com.zbkc.mamclient.util.IOUtilsEx;
import com.zbkc.mamclient.util.ThreadPoolFactory;
import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;


/**
* Created by IntelliJ IDEA.
* User: 罗代均
* Date: 2010-8-23
* Time: 1:05:37
*/
public class WebImageView extends ImageView {

    private final static String TAG = WebImageView.class.getName();

    private Handler handler = new Handler();

    public WebImageView(Context context) {
        super(context);
    }

    public WebImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public WebImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * @param url       图片的URL地址
     * @param cacheFile 图片第一次下载后,存到本地文件,下次不用网络下载
     */
    public void setImageUrl(final String url, final File cacheFile) {

        Log.d(TAG, "load image,url:" + url + ",cacheFile:" + cacheFile.getAbsolutePath());

        File dir = cacheFile.getParentFile();
        if (!dir.exists()) {
            dir.mkdirs();
        }

        if (cacheFile.exists()) {
            setImageBitmap(BitmapFactory.decodeFile(cacheFile.getAbsolutePath()));
            return;
        }

        ThreadPoolFactory.getInstance().execute(new Runnable() {
            public void run() {
                try {
                    IOUtilsEx.copyUrl(url, new FileOutputStream(cacheFile));

                    handler.post(new Runnable() {
                        public void run() {
                            setImageBitmap(BitmapFactory.decodeFile(cacheFile.getAbsolutePath()));
                        }
                    });
                } catch (Exception e) {
                    Log.e(TAG, "setImageUrl error", e);
                }

            }
        });
    }


    public void setImageUrl(final String url) {
        Log.d(TAG, "load image,url:" + url);

        ThreadPoolFactory.getInstance().execute(new Runnable() {
            public void run() {
                InputStream is = null;
                try {
                    is = new URL(url).openStream();
                    final Bitmap bmp = BitmapFactory.decodeStream(is);
                    handler.post(new Runnable() {
                        public void run() {
                            setImageBitmap(bmp);
                        }
                    });
                } catch (Exception e) {
                    Log.e(TAG, "setImageUrl error", e);
                } finally {
                    IOUtils.closeQuietly(is);
                }

            }
        });
    }
}
0 请登录后投票
   发表时间:2010-08-24  
ls 和我的做法一样 保存到本地。

File dir = cacheFile.getParentFile();
        if (!dir.exists()) {
            dir.mkdirs();
        }

这个判断 我那到其他地方去了,就不用每次都判断一次。

ThreadPoolFactory 线程池? 我对这个不太熟悉 有什么特别的好处吗?

你是怎么实现的?

还有 我的 imageView 在listView里面 下载完之后 还要更新视图 感觉有点怪怪的。
不知道 有没什么好的方法
0 请登录后投票
   发表时间:2010-08-24  
学android居然没有加入组织。落后了啊

搜索下hong老大的坛子。
0 请登录后投票
   发表时间:2010-08-24  
aa87963014 写道
ls 和我的做法一样 保存到本地。

File dir = cacheFile.getParentFile();
        if (!dir.exists()) {
            dir.mkdirs();
        }

这个判断 我那到其他地方去了,就不用每次都判断一次。

ThreadPoolFactory 线程池? 我对这个不太熟悉 有什么特别的好处吗?

你是怎么实现的?

还有 我的 imageView 在listView里面 下载完之后 还要更新视图 感觉有点怪怪的。
不知道 有没什么好的方法


这个判断性能影响有限,主要是为了这个控件更加健壮,线程池用Java自带的
package com.zbkc.mamclient.util;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* Created by IntelliJ IDEA.
* User: 罗代均
* Date: 2010-8-5
* Time: 21:14:02
* 线程池
*/
public class ThreadPoolFactory {
    private static ThreadPoolFactory ourInstance = new ThreadPoolFactory();

    public static ThreadPoolFactory getInstance() {
        return ourInstance;
    }

    private ExecutorService threadPool;

    private ThreadPoolFactory() {
        threadPool = Executors.newCachedThreadPool();
    }


    /**
     * 提交给线程池执行
     *
     * @param run
     */
    public void execute(Runnable run) {
        threadPool.submit(run);
    }
}


0 请登录后投票
   发表时间:2010-08-24  
IO操作工具类,其实是包装了apache commons-io

package com.zbkc.mamclient.util;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
* Created by IntelliJ IDEA.
* User: 罗代均
* Date: 2010-8-23
* Time: 0:17:32
*/
public class IOUtilsEx extends IOUtils {

    /**
     * 拷贝URL内容到输出流
     *
     * @param srcUrl
     */
    public static void copyUrl(String srcUrl, OutputStream destOutpstream) {
        InputStream is = null;
        HttpEntity entity = null;
        HttpClient client = null;
        try {
            client = new DefaultHttpClient();
            HttpGet get = new HttpGet(srcUrl);
            HttpResponse response = client.execute(get);
            entity = response.getEntity();
            is = entity.getContent();
            copy(is, destOutpstream);
        } catch (IOException ex) {

        } finally {
            if (entity != null) {
                try {
                    entity.consumeContent();
                } catch (IOException e) {

                }
            }
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(destOutpstream);
        }
    }
}
0 请登录后投票
   发表时间:2010-08-25  
圈子加了是加了。但是好像不是很活跃。

坛子?圈子? 还是 q q 群?
0 请登录后投票
   发表时间:2010-08-29  
我也发现了内存溢出的情况,请要怎么去处理呀!
0 请登录后投票
论坛首页 移动开发技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics