UIL中包括一下封裝的任務(wù):
- DisplayImageTask
- LoadAndDisplayImageTask
- ProcessAndDisplayImageTask
它們都在ImageLoadEngine中得到統(tǒng)一調(diào)度執(zhí)行。
線程需要關(guān)注的幾個(gè)方面:
線程池類型
創(chuàng)建線程池的構(gòu)造方法:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}

幾種常見(jiàn)線程池.png
- 對(duì)于需要保證所有提交的任務(wù)都要被執(zhí)行的情況,或者任務(wù)屬于耗時(shí)長(zhǎng)但是數(shù)量少的,使用FixedThreadPool
- 如果限定只能使用一個(gè)線程進(jìn)行任務(wù)處理,使用SingleThreadExecutor
- 如果希望提交的任務(wù)盡快分配線程執(zhí)行,或者說(shuō)任務(wù)量大且每個(gè)任務(wù)耗時(shí)比較少的,使用CachedThreadPool
- 如果業(yè)務(wù)上允許任務(wù)執(zhí)行失敗,或者任務(wù)執(zhí)行過(guò)程可能出現(xiàn)執(zhí)行時(shí)間過(guò)長(zhǎng)進(jìn)而影響其他業(yè)務(wù)的應(yīng)用場(chǎng)景,可以通過(guò)使用限定線程數(shù)量的線程池以及限定長(zhǎng)度的隊(duì)列進(jìn)行容錯(cuò)處理。

UIL中的三個(gè)線程池.png

UIL中線程池的配置.png
UIL線程執(zhí)行
ImageLoader
ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,
options, listener, progressListener, engine.getLockForUri(uri));
LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo,
defineHandler(options));
if (options.isSyncLoading()) {
displayTask.run();
} else {
engine.submit(displayTask);
}
ImageLoadEngine
void submit(final LoadAndDisplayImageTask task) {
taskDistributor.execute(new Runnable() {
@Override
public void run() {
File image = configuration.diskCache.get(task.getLoadingUri());
boolean isImageCachedOnDisk = image != null && image.exists();
initExecutorsIfNeed();
if (isImageCachedOnDisk) {
taskExecutorForCachedImages.execute(task);
} else {
taskExecutor.execute(task);
}
}
});
}
- taskDistributor:主要任務(wù)就是根據(jù)磁盤(pán)是否有緩存,再來(lái)分配任務(wù)。由于在每創(chuàng)建一個(gè)新的線程的時(shí)候都需要讀取一下磁盤(pán),屬于IO操作。需要圖片緩存的應(yīng)用一般在需要加載圖片的時(shí)候,同時(shí)創(chuàng)建很多(>5)線程,這些線程一般來(lái)得猛去的也快,存活時(shí)間不必太長(zhǎng)。
- taskExecutorForCachedImages:主要任務(wù)就是將磁盤(pán)上緩存的圖片解碼出來(lái),并作后續(xù)處理,再顯示
- taskExecutor:主要任務(wù)就是負(fù)責(zé)一個(gè)圖片完整的從網(wǎng)絡(luò)加載到磁盤(pán)緩存、內(nèi)存緩存、預(yù)處理、后續(xù)處理、展示等。
它有如下幾個(gè)主要方法:
private Executor createTaskExecutor() {
return DefaultConfigurationFactory
.createExecutor(configuration.threadPoolSize, configuration.threadPriority,
configuration.tasksProcessingType);
}
void pause() {
paused.set(true);
}
void resume() {
paused.set(false);
synchronized (pauseLock) {
pauseLock.notifyAll();
}
}
void stop() {
if (!configuration.customExecutor) {
((ExecutorService) taskExecutor).shutdownNow();
}
if (!configuration.customExecutorForCachedImages) {
((ExecutorService) taskExecutorForCachedImages).shutdownNow();
}
cacheKeysForImageAwares.clear();
uriLocks.clear();
}
其中shutdownNow()方法會(huì)終止線程池中的執(zhí)行
而這個(gè)pause()和resume()方法,在多圖列表滑動(dòng)時(shí),可以通過(guò)調(diào)用此方法,暫停線程池中任務(wù)的執(zhí)行以減輕cpu的負(fù)擔(dān),達(dá)到流暢滑動(dòng)的目的。
在LoadAndDisplayImageTask中,run()方法執(zhí)行之前,都會(huì)檢查一下 waitIfPaused()方法看此任務(wù)是否暫停,如果是,則先把線程鎖鎖上,然后進(jìn)入等待。
private boolean waitIfPaused() {
AtomicBoolean pause = engine.getPause();
if (pause.get()) {
synchronized (engine.getPauseLock()) {
if (pause.get()) {
L.d(LOG_WAITING_FOR_RESUME, memoryCacheKey);
try {
engine.getPauseLock().wait();
} catch (InterruptedException e) {
L.e(LOG_TASK_INTERRUPTED, memoryCacheKey);
return true;
}
L.d(LOG_RESUME_AFTER_PAUSE, memoryCacheKey);
}
}
}
return isTaskNotActual();
}