##简介
我曾在之前的一个项目中研究过这个主题,并发现了不同的解决方案。最终,我选择了第一种方法,因为它最适合那个具体的项目。
假设有一个名为ImageDownloader
的类来异步下载来自URL的图像,它具有以下属性。
- 一个接口 -
ImageDownloadCallback
用于在任务完成时获取回调。它有两种方法
void onSuccess(String imagePath)
:任务成功完成时调用。
void onFailure()
:任务未能完成时调用。
- 一个方法 -
download(String url, ImageDownloadCallback callback)
用于启动下载任务
PauseModeCallbackHandler
、ChainModeCallbackHandler
和ParallelModeCallbackHandler
分别是三种方法的回调包装类。您可以根据要执行的任务进行自定义。
##方法1:
通过暂停启动线程一个接一个地执行任务。
优点
在原始线程中获取结果
缺点
需要使线程等待
import java.util.concurrent.atomic.AtomicReference;
public class ThreadLockedTask<T> {
private AtomicReference<ResultWrapper<T>> mReference;
public ThreadLockedTask() {
mReference = new AtomicReference<>(new ResultWrapper<T>());
}
public T execute(Runnable runnable) {
runnable.run();
if (!mReference.get().mIsSet)
lockUntilSet();
return mReference.get().mResult;
}
private void lockUntilSet() {
synchronized (this) {
while (!mReference.get().isSet()) {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public void setResult(T result) {
synchronized (this) {
ResultWrapper<T> wrapper = mReference.get();
wrapper.setResult(result);
wrapper.setIsSet(true);
notify();
}
}
public static class ResultWrapper<T> {
private boolean mIsSet;
private T mResult;
public boolean isSet() {
return mIsSet;
}
public T getResult() {
return mResult;
}
void setIsSet(boolean isCompleted) {
this.mIsSet = isCompleted;
}
void setResult(T result) {
this.mResult = result;
}
}
}
###示例
import java.util.ArrayList;
import java.util.List;
public class PauseModeCallbackHandler {
private static List<String> results;
public static void start(final List<String> urls, final ImageDownloader.ProgressUpdateListener listener) {
new Thread(new Runnable() {
@Override
public void run() {
results = new ArrayList<>();
for (final String url :
urls) {
final ThreadLockedTask<String> task = new ThreadLockedTask<>();
final String imagePath = task.execute(new Runnable() {
@Override
public void run() {
ImageDownloader.getInstance(listener).download(url,
new ImageDownloader.ImageDownloadCallback() {
@Override
public void onSuccess(String imagePath) {
task.setResult(imagePath);
}
@Override
public void onFailure() {
task.setResult(null);
}
});
}
});
if (imagePath!=null)
results.add(imagePath);
}
afterCallbacks();
}
}).start();
}
private PauseModeCallbackHandler() {}
private static void afterCallbacks() {
DemoActivity.isTasksInProgress = false;
}
}
##方法 2:
像连锁反应一样从上一个回调函数执行下一个任务。
示例
import java.util.ArrayList;
import java.util.List;
public class ChainModeCallbackHandler implements ImageDownloader.ImageDownloadCallback {
private static List<String> urls;
private static List<String> results;
private static ImageDownloader.ProgressUpdateListener progressUpdateListener;
private int index;
public static void start(List<String> urls, ImageDownloader.ProgressUpdateListener listener) {
ChainModeCallbackHandler.urls = urls;
results = new ArrayList<>();
progressUpdateListener = listener;
ImageDownloader.getInstance(listener).download(urls.get(0), new ChainModeCallbackHandler(0));
}
private ChainModeCallbackHandler(int index) {
this.index = index;
}
@Override
public void onSuccess(String imagePath) {
results.add(imagePath);
afterCallback();
}
@Override
public void onFailure() {
afterCallback();
}
private void afterCallback() {
int nextIndex = index+1;
if (nextIndex<urls.size()) {
ImageDownloader.getInstance(progressUpdateListener).download(urls.get(nextIndex),
new ChainModeCallbackHandler(nextIndex));
} else {
DemoActivity.isTasksInProgress = false;
}
}
}
##方法三:
并行执行任务。
优点
并行执行有时可以节省时间。
示例
import java.util.ArrayList;
import java.util.List;
public class ParallelModeCallbackHandler {
private static List<String> urls;
private static List<String> results;
private static int count;
public static void start(List<String> urls, ImageDownloader.ProgressUpdateListener listener) {
ParallelModeCallbackHandler.urls = urls;
results = new ArrayList<>();
count = 0;
for (String url :
urls) {
ImageDownloader.getInstance(listener).download(url, new ImageDownloader.ImageDownloadCallback() {
@Override
public void onSuccess(String imagePath) {
results.add(imagePath);
afterCallback();
}
@Override
public void onFailure() {
afterCallback();
}
});
}
}
private ParallelModeCallbackHandler() {}
private static void afterCallback() {
if (++count==urls.size()) {
DemoActivity.isTasksInProgress = false;
}
}
}