如何使用ThreadPool 來下載網路圖片

如何使用ThreadPool 來下載網路圖片

可以直接使用Glide套件下載會更方便

可以參考如何使用Glide

在之前如何從網路下載圖片的文章是下載一張圖片,
那如果要在listview內下載圖片,
又不想要影響滑動怎麼辦呢?
在網路圖片還沒下載好之前, 就先用預設圖片來裝一下就好。
可以自由滑動直到網路圖片下載完畢再更新。

根據如何從網路下載圖片的程式碼修改

public void handleWebPic(final String url, final int index){

    ThreadPoolManager.getInstance()
    .addSelectPhotoTask(new Thread(new Runnable(){
        @Override
        public void run() {      
            Bitmap bmp = getUrlPic(url);
            bmpList.add(index, bmp);
            runOnUiThread(new Runnable(){
                @Override
                public void run() {     
                    if(mMyAdapter != null){
                        mMyAdapter.notifyDataSetChanged();
                    }
                }  
            });  
        } 
    }));
}

public synchronized Bitmap getUrlPic(String url) {
    Bitmap webImg = null;  
    try {
        URL imgUrl = new URL(url);
        HttpURLConnection httpURLConnection 
                = (HttpURLConnection) imgUrl.openConnection();
        httpURLConnection.connect();
        InputStream inputStream = httpURLConnection.getInputStream();
        int length = (int) httpURLConnection.getContentLength();
        int tmpLength = 512;
        int readLen = 0,desPos = 0;
        byte[] img = new byte[length];
        byte[] tmp = new byte[tmpLength];
        if (length != -1) {
            while ((readLen = inputStream.read(tmp)) > 0) {
                System.arraycopy(tmp, 0, img, desPos, readLen);
                desPos += readLen;
            }
            webImg = BitmapFactory.decodeByteArray(img, 0,img.length);
            if(desPos != length){
                throw new IOException("Only read" + desPos +"bytes");
            }
        }
        httpURLConnection.disconnect();
    }
    catch (IOException e) {
        Log.e("IOException",e.toString());
    }
    return webImg;
}

當抓完網路圖片以後, 則丟到一個圖片陣列內

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mContext = getApplicationContext();
    mListView = (ListView) findViewById(R.id.listview);
    bmpList = new ArrayList<Bitmap>();
    for(int i = 0; i < 100; i++){
        bmpList.add(null);
      handleWebPic("https://dl.dropboxusercontent.com/u/24682760/drawable/raccoon.png", i);
    }
    mMyAdapter = new MyAdapter();
    mListView.setAdapter(mMyAdapter);
}

一開始宣告一個listview 跟 adapter, 然後假設我們要抓一百張圖片,
因為我懶所以抓同一張, 不影響結果。

那如果他一開始還沒有圖片, 就讓這個bitmap為null。

private class MyAdapter extends BaseAdapter{

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return bmpList.size();
    }

    @Override
    public Object getItem(int arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public long getItemId(int arg0) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public View getView(int position, View view, ViewGroup arg2) {
        View v = view;
        Holder holder;
        if(v == null){
            v = LayoutInflater.from(mContext).inflate(R.layout.listview_item, null);
            holder = new Holder();
            holder.img = (ImageView) v.findViewById(R.id.img);
            v.setTag(holder);
        } else{
            holder = (Holder) v.getTag();
        }
        if(bmpList.get(position) == null){
            holder.img.setImageResource(R.drawable.ic_launcher);
        } else{
            holder.img.setImageBitmap(bmpList.get(position));
        }
        return v;
    }
    class Holder{
        ImageView img;
    }
}

關鍵字就是圖片為null的時候, 表示還沒下載完, 所以就讓他為預設圖片,
否則就刷新呈現出來。

至於thradpool要怎麼使用呢?

public class ThreadPoolManager {

    private static ThreadPoolManager mThreadPoolManager;

    private final int KEEP_ALIVE_TIME = 3;
    // Sets the Time Unit to seconds
    private final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
    // Creates a thread pool manager

    private ThreadPoolManager(){}

    public static ThreadPoolManager getInstance(){
        if(null == mThreadPoolManager){
            mThreadPoolManager = new ThreadPoolManager();
        }
        return mThreadPoolManager;
    }

    private final BlockingQueue<Runnable> mPhotoQueue = new LinkedBlockingQueue<Runnable>();

    private ThreadPoolExecutor mPhotoExcutor = new ThreadPoolExecutor(
            4,       // Initial pool size
            5,       // Max pool size
            KEEP_ALIVE_TIME,
            KEEP_ALIVE_TIME_UNIT,
            mPhotoQueue);

    public void addSelectPhotoTask(Runnable runnable){
        mPhotoExcutor.execute(runnable);
    }
}

寫一個獨體模式 讓他去跑thread 利用內建的排程LinkedBlockingQueue (還有很多種)
讓他用佇列一個一個跑完以後, 就對畫面做更新。

這樣就完成一個簡單的排程。