从零开始编写图片加载库(三)之线程池图片下载

1.简介

我们知道在开发应用程序时候,有时候下载图片的操作是很多的,但是我们又不能不能在UI线程里面去执行网络操作,并且android系统要求我们在执行完网络操作后更新UI,前面两篇文章介绍了通过AsyncTask和Handler+Thread的方式更新UI。这篇文章介绍通过线程池的方式处理线程。

2.ExecutorService的介绍

An {@code ExecutorService} can be shut down, which will cause it to reject new tasks. Two different methods are provided for shutting down an {@code ExecutorService}. The {@link #shutdown} method will allow previously submitted tasks to execute before terminating, while the {@link #shutdownNow} method prevents waiting tasks from starting and attempts to stop currently executing tasks. Upon termination, an executor has no tasks actively executing, no tasks awaiting execution, and no new tasks can be submitted. An unused {@code ExecutorService} should be shut down to allow reclamation of its resources.(摘自源代码)


意思是ExecutorService可以停止执行当前线程,并且子方法shutdown和shutdownnow的停止方式不一样,shutdown会等当前任务执行完再停止,shutdowndow是立即停止。

2.1NetworkService、Executors和ThreadPoolExecutor之间的关系

ThreadPoolExecutor继承AbstractExecutorService,而AbstractExecutorService实现了NetworkService里面定义的方法,ThreadPoolExecutor是创建线程池的工人,NetworkService有点像包工头,接活然后把活给ThreadPoolExecutor干,Executors主要是管理NetworkService的一些需求然后将需求直接传达给ThreadPoolExecutor。

Executors里面提供的一个创建NetworkService方法。

   public static ExecutorService newFixedThreadPool(int nThreads){
        return new ThreadPoolExecutor(nThreads,nThreads,
        0L,TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>());
        }

2.2一个NetworkService实例

  class NetworkService implements Runnable {
    private final ServerSocket serverSocket;
    private final ExecutorService pool;

    public NetworkService(int port, int poolSize)
            throws IOException {
        serverSocket = new ServerSocket(port);
        //创建一个线程池
        pool = Executors.newFixedThreadPool(poolSize);
    }

    public void run() { // run the service
        try {
            for (; ; ) {
                //将当前任务抛到线程池当中执行
                pool.execute(new Handler(serverSocket.accept()));
            }
        } catch (IOException ex) {
            pool.shutdown();
        }
    }
}

class Handler implements Runnable {
    private final Socket socket;

    Handler(Socket socket) {
        this.socket = socket;
    }

    public void run() {
        // read and service request on socket
    }
}

上面通过Executors.newFixedThreadPool(poolSize)创建线程,通过查看Executors,Executors.newFixedThreadPool(poolSize)调用了:

 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

再往里看:

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

ok就到这里,线程池中有一个corePoolSize就是在线程池中始终保持的数量,maximumPoolSize就是如果在当前线程池创建的线程都被在占用的时候,可以多创建maximumPoolSize-corePoolSize个线程保证任务执行。如果还是不够的话,未被执行的任务只能等待当前任务执行完成才可以被执行。

3.android里面通过线程池下载图片

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

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.widget.ImageView;

import cn.sundroid.imageloader.listener.ImageLoaderListener;
import cn.sundroid.imageloader.thread.LoadBitmapTask;

public class MainActivity extends Activity {
    private ImageView image;
    //创建线程池服务
    private ExecutorService executorService = Executors.newFixedThreadPool(Thread.NORM_PRIORITY - 2);
    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        image = (ImageView) findViewById(R.id.image);
        handler = new Handler();
        LoadBitmapTask task = new LoadBitmapTask(new ImageLoaderListener() {
            @Override
            public void onLoadFinished(Bitmap bitmap) {
                image.setImageBitmap(bitmap);
            }
        }, handler);
        //将任务抛到线程池中执行
        executorService.execute(task);
    }

}

之前说过由于必须在主线程中更新UI,所以我们在UI线程中创建了一个Handler并且传到Task中。

import java.io.InputStream;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;

import cn.sundroid.imageloader.downloader.ImageDownloader;
import cn.sundroid.imageloader.listener.ImageLoaderListener;
import cn.sundroid.imageloader.utils.Constants;

public class LoadBitmapTask implements Runnable {
    private ImageLoaderListener listener;
    private Handler handler;

    public LoadBitmapTask(ImageLoaderListener listener, Handler handler) {
        super();
        this.listener = listener;
        this.handler = handler;
    }

    @Override
    public void run() {
        InputStream is = ImageDownloader.getStream(Constants.image_url0);
        final Bitmap bitmap = BitmapFactory.decodeStream(is);

        handler.post(new Runnable() {
            @Override
            public void run() {
                if (listener != null) {
                    listener.onLoadFinished(bitmap);
                }
            }
        });

    }

}

并且通过handler的post方法执行这个Runnable。

 Causes the Runnable r to be added to the message queue.The runnable 
 will be run on the thread to which this handler is attached. 

这个解释就不多说了,好了就到这里,执行结果就不贴了和之前的一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值