仍旧沿用ExecutorService的例子, 修改了AsyncImageLoader调用线程管理池的方法。
AsyncImageLoader的思路:
1. 自定义RejectedExecutionHandler, 当线程任务被拒绝时,使其等待线程管理池空余后继续被调用。
2. 自定义线程管理池ThreadPoolExecutor替代ExecutorService
3. 线程的主要任务DownloadThreadTask,加载图片
4. 所有任务完成后,关闭自定义的ThreadPoolExecutor
源码:
自定义的RejectedExecutionHandler
自定义的ThreadPoolExecutor
线程任务DownloadThreadTask
AsyncImageLoader
下载的Activity对AsyncImageLoader的调用
---------------------------------------------------------------
以下使用 Callable 替代Runnable来进行图片的加载。 思路如上述所,只是修改一些源码。
1. 加载图片的 Callable
2. AsyncCallableLoader 替代 AsyncImageLoader
3. Activity调用AsnycCallableLoader
AsyncImageLoader的思路:
1. 自定义RejectedExecutionHandler, 当线程任务被拒绝时,使其等待线程管理池空余后继续被调用。
2. 自定义线程管理池ThreadPoolExecutor替代ExecutorService
3. 线程的主要任务DownloadThreadTask,加载图片
4. 所有任务完成后,关闭自定义的ThreadPoolExecutor
源码:
自定义的RejectedExecutionHandler
public class RejectedExcutionHandlerImpl implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
Log.i("test", ((DownloadThreadTask)r).getTask() + " is rejected");
// 如果出现线程任务被拒绝,则等待一段时间后,再次创建并提交到线程池中
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executor.execute(r);
Log.i("test",((DownloadThreadTask)r).getTask() + "再次创建并提交");
}
}
自定义的ThreadPoolExecutor
public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
public CustomThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler){
super(corePoolSize,maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
// beforeExecute, afterExecute方法一般用于日志中,记录任务被调用前和完成后的状态
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
Log.i("test","perform before execute logic" + ((DownloadThreadTask)r).getTask());
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t != null) {
Log.i("test","Perform exception handler logic" + ((DownloadThreadTask)r).getTask());
}
Log.i("test","Perform afterExecute() logic" + ((DownloadThreadTask)r).getTask());
}
}
线程任务DownloadThreadTask
public class DownloadThreadTask implements Runnable {
public Map<String, SoftReference<Drawable>> imageCache = new HashMap<String,SoftReference<Drawable>>();
private String task; // 任务名称
private String url; // 加载URL
private Handler handler;
private ImageCallback callback;
public DownloadThreadTask(String task, String url, Handler handler, ImageCallback callback){
this.task = task;
this.url = url;
this.handler = handler;
this.callback = callback;
}
public String getTask() {
return task;
}
public void setTask(String task) {
this.task = task;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
@Override
public void run() {
try {
try{
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}
final Drawable drawable = loadImageFromUrl(url);
imageCache.put(url, new SoftReference<Drawable>(drawable));
handler.post(new Runnable() {
public void run() {
callback.imageLoader(drawable);
}
});
Log.i("test", "加载图片任务完成" + this.task);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
protected Drawable loadImageFromUrl(String imageUrl){
try {
return Drawable.createFromStream(new URL(imageUrl).openStream(), "image.png");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
AsyncImageLoader
public class AsyncImageLoader {
public Map<String, SoftReference<Drawable>> imageCache = new HashMap<String,SoftReference<Drawable>>();
private BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(2);
private RejectedExecutionHandler myReject = new RejectedExcutionHandlerImpl();
CustomThreadPoolExecutor executor = new CustomThreadPoolExecutor(1,2,5,TimeUnit.MILLISECONDS, blockingQueue, myReject);
private final Handler handler = new Handler();
public Drawable loadDrawable(final String task, final String imageUrl, final ImageCallback callback){
if(imageCache.containsKey(imageUrl)){
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
if(softReference.get()!=null){
return softReference.get();
}
}
Log.i("test","创建任务并提交到线程池中:" + task);
executor.execute(new DownloadThreadTask(task, imageUrl, handler, callback));
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
public void shutdownAndAwaitTermination() {
executor.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
Log.i("test", "i am shutting down...");
if (!executor.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
}catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
Log.e("test","something interrupted happend, and i am shutting down....");
executor.shutdownNow();
// Preserve interrupt status
//Thread.currentThread().interrupt();
}
}
}
下载的Activity对AsyncImageLoader的调用
public class BatchDownloadActivity extends Activity {
private static final String fileRealName = "我的图片1.gif";
private String url;
private int id;
private List<String> urls = new ArrayList<String>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.batch_download);
String fileName = fileRealName;
String url = "";
try {
url = ToolsUtil.getIpAddress() + URLEncoder.encode(fileRealName,"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Log.i("test","url=" + url);
loadImage("task@1", url, R.id.imageView1);
loadImage("task@2", url, R.id.imageView2);
loadImage("task@3", url, R.id.imageView3);
loadImage("task@4", url,R.id.imageView4);
loadImage("task$5", url,R.id.imageView5);
loader.shutdownAndAwaitTermination();
}
private AsyncImageLoader loader = new AsyncImageLoader();
private void loadImage(final String task, final String url, final int id) {
Drawable cacheImage = loader.loadDrawable(task, url,new ImageCallback() {
@Override
public void imageLoader(Drawable imageDrawable) {
((ImageView) findViewById(id)).setImageDrawable(imageDrawable);
Log.i(task, "loading new pic:" +url);
}
});
if (cacheImage != null) {
((ImageView) findViewById(id)).setImageDrawable(cacheImage);
Log.i("test", "loading existing pic");
}
}
}
---------------------------------------------------------------
以下使用 Callable 替代Runnable来进行图片的加载。 思路如上述所,只是修改一些源码。
1. 加载图片的 Callable
public class DownloadCallableTask implements Callable<Drawable> {
public Map<String, SoftReference<Drawable>> imageCache = new HashMap<String,SoftReference<Drawable>>();
private String task;
private String url;
public DownloadCallableTask(String task, String url){
this.task = task;
this.url = url;
}
public String getTask(){
return this.task;
}
@Override
public Drawable call() throws Exception {
try{
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}
if(imageCache.containsKey(url)){
SoftReference<Drawable> softReference = imageCache.get(url);
if(softReference.get()!=null){
return softReference.get();
}
}
final Drawable drawable = loadImageFromUrl(url);
imageCache.put(url, new SoftReference<Drawable>(drawable));
Log.i("test", "加载图片任务完成" + this.task);
return drawable;
}
protected Drawable loadImageFromUrl(String imageUrl){
try {
return Drawable.createFromStream(new URL(imageUrl).openStream(), "image.png");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
2. AsyncCallableLoader 替代 AsyncImageLoader
public class AsyncCallableLoader {
private BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(2);
ThreadPoolExecutor executor = new ThreadPoolExecutor(1,2,5,TimeUnit.MILLISECONDS, blockingQueue);
private final Handler handler = new Handler();
public Drawable loadDrawable(final String task, final String imageUrl) throws InterruptedException, ExecutionException{
Log.i("test","创建任务并提交到线程池中:" + task);
final Future<Drawable> future = executor.submit(new DownloadCallableTask(task,imageUrl));
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return future.get();
}
public void shutdownAndAwaitTermination() {
executor.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
Log.i("test", "i am shutting down...");
if (!executor.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
}catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
Log.e("test","something interrupted happend, and i am shutting down....");
executor.shutdownNow();
// Preserve interrupt status
//Thread.currentThread().interrupt();
}
}
}
3. Activity调用AsnycCallableLoader
private AsyncCallableLoader loader = new AsyncCallableLoader();
private void loadImage(final String task, final String url, final int id) {
Drawable cacheImage;
try {
cacheImage = loader.loadDrawable(task, url);
if (cacheImage != null) {
((ImageView) findViewById(id)).setImageDrawable(cacheImage);
Log.i("test", "loading pic");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}