class PhotoDecodeRunnable implements Runnable {
...
/*
* Defines the code to run for this task.
*/
@Override
public void run() {
// Moves the current Thread into the background
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
...
/*
* Stores the current Thread in the the PhotoTask instance,
* so that the instance
* can interrupt the Thread.
*/
mPhotoTask.setImageDecodeThread(Thread.currentThread());
...
}
...
}
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
这句话可以将你的线程移动到后台。(该优先级低于主线程,避免与主线程竞争CPU)
这里以PhotoManager为例:
1.既然是个管理者,最好是单例:(至于如何创建单例,不解释了)
public class PhotoManager {
...
static {
...
// Creates a single static instance of PhotoManager
sInstance = new PhotoManager();
}
/**
* Constructs the work queues and thread pools used to download
* and decode images. Because the constructor is marked private,
* it's unavailable to other classes, even in the same package.
*/
private PhotoManager() {
...
}
...
2.启动一个照片下载任务,通过线程池,从队列中取一个runnable也就是任务对象:
public class PhotoManager {
...
// Called by the PhotoView to get a photo
static public PhotoTask startDownload(
PhotoView imageView,
boolean cacheFlag) {
...
// Adds a download task to the thread pool for execution
sInstance.
mDownloadThreadPool.
execute(downloadTask.getHTTPDownloadRunnable());
...
}
3.自定义Handler来更新UI
private PhotoManager() {
...
// Defines a Handler object that's attached to the UI thread
mHandler = new Handler(Looper.getMainLooper()) {
/*
* handleMessage() defines the operations to perform when
* the Handler receives a new Message to process.
*/
@Override
public void handleMessage(Message inputMessage) {
...
}
...
}
}
4.决定线程池的参数:初始化的线程池大小和最大池大小
首先ThreadPoolExcutor是android定义的类,不是java.
那么线程池的大小如何决定?最大又该多少呢?
答:省事点:通过Runtime.getRuntime().availableProcessors()
public class PhotoManager {
...
/*
* Gets the number of available cores
* (not always the same as the maximum number of cores)
*/
private static int NUMBER_OF_CORES =
Runtime.getRuntime().availableProcessors();
}
5.决定线程池的参数:空闲线程持续时间。(keep alive time),单位通过TimeUnit。
6.任务队列:可以使用LinkedBlockingQueue<Runnable>
public class PhotoManager {
...
private PhotoManager() {
...
// A queue of Runnables
private final BlockingQueue<Runnable> mDecodeWorkQueue;
...
// Instantiates the queue of Runnables as a LinkedBlockingQueue
mDecodeWorkQueue = new LinkedBlockingQueue<Runnable>();
...
}
...
}
7.好,下面进入创建线程池:
private PhotoManager() {
...
// Sets the amount of time an idle thread waits before terminating
private static final int KEEP_ALIVE_TIME = 1;
// Sets the Time Unit to seconds
private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
// Creates a thread pool manager
mDecodeThreadPool = new ThreadPoolExecutor(
NUMBER_OF_CORES, // Initial pool size
NUMBER_OF_CORES, // Max pool size
KEEP_ALIVE_TIME,
KEEP_ALIVE_TIME_UNIT,
mDecodeWorkQueue);
}
8.让线程池执行一个任务试试:ThreadPoolExecutor.execute()会将该任务加入到线程池的队列中。当一个空闲的线程变得可用时,Manager会将等待时间最长的任务运行在这个线程中。
public class PhotoManager {
public void handleState(PhotoTask photoTask, int state) {
switch (state) {
// The task finished downloading the image
case DOWNLOAD_COMPLETE:
// Decodes the image
mDecodeThreadPool.execute(
photoTask.getPhotoDecodeRunnable());
...
}
...
}
...
}
9.打断正在执行任务的某个或者所有线程
public class PhotoManager {
public static void cancelAll() {
/*
* Creates an array of Runnables that's the same size as the
* thread pool work queue
*/
Runnable[] runnableArray = new Runnable[mDecodeWorkQueue.size()];
// Populates the array with the Runnables in the queue
mDecodeWorkQueue.toArray(runnableArray);
// Stores the array length in order to iterate over the array
int len = runnableArray.length;
/*
* Iterates over the array of Runnables and interrupts each one's Thread.
*/
synchronized (sInstance) {
// Iterates over the array of tasks
for (int runnableIndex = 0; runnableIndex < len; runnableIndex++) {
// Gets the current thread
Thread thread = runnableArray[taskArrayIndex].mThread;
// if the Thread exists, post an interrupt to it
if (null != thread) {
thread.interrupt();
}
}
}
}
...
}
注意:大多数情况,Thread.interrupt()可以马上把线程打断掉。但是只能打断在等待的线程,不能打断CPU或者网络任务的线程。为了避免减缓或则锁住系统。你应该在尝试操作前,验证是否被打断。
/*
* Before continuing, checks to see that the Thread hasn't
* been interrupted
*/
if (Thread.interrupted()) {
return;
}
...
// Decodes a byte array into a Bitmap (CPU-intensive)
BitmapFactory.decodeByteArray(
imageBuffer, 0, imageBuffer.length, bitmapOptions);
...