package com.silencedut.knowweather.scheduler;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Process;
import android.support.annotation.NonNull;
import com.silencedut.knowweather.scheduler.exception.ErrorBundle;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by SilenceDut on 16/10/28.
*/
public class TaskScheduler {
private static final AtomicInteger mHandlerCount = new AtomicInteger(1);
private static ExecutorService mParallelExecutor ;
private static ExecutorService mTimeOutExecutor ;
private static Handler sMainHandler = new Handler(Looper.getMainLooper());
private static Handler sBackgroundHandler ;
private static boolean sInited;
private static final int POOL_SIZE = 2;
private static final int MAX_POOL_SIZE = 5;
private static final int TIMEOUT = 30;
private TaskScheduler() {
}
public static void init() {
if(sInited) {
return;
}
mParallelExecutor = new ThreadPoolExecutor(POOL_SIZE, MAX_POOL_SIZE, TIMEOUT,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(MAX_POOL_SIZE*2),sThreadFactory);
mTimeOutExecutor = Executors.newCachedThreadPool(sTimeOutThreadFactory);
HandlerThread handlerThread = new HandlerThread("background",Process.THREAD_PRIORITY_BACKGROUND);
handlerThread.start();
sBackgroundHandler = new Handler(handlerThread.getLooper());
sInited = true;
}
public static Handler provideHandler() {
String handlerName = "BackgroundHandler #" + mHandlerCount.getAndIncrement();
return provideHandler(handlerName);
}
public static Handler provideHandler(String handlerName) {
HandlerThread handlerThread = new HandlerThread(handlerName,Process.THREAD_PRIORITY_BACKGROUND);
handlerThread.start();
return new Handler(handlerThread.getLooper());
}
public static void execute(Runnable task) {
mParallelExecutor.execute(runnableToTask(task));
}
public static <R> void execute(Task<R> task) {
mParallelExecutor.execute(task);
}
/**
* 使用一个单独的线程池来执行超时任务,避免引起他线程不够用导致超时
** 通过实现error(Exception) 判断是否为 TimeoutException 来判断是否超时
* */
public static <R> void execute(final long timeOutMilliSecond, final Task<R> timeOutTask) {
final Future future = mTimeOutExecutor.submit(timeOutTask);
mTimeOutExecutor.execute(new Runnable() {
@Override
public void run() {
try {
future.get(timeOutMilliSecond,TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e ) {
runOnUIThread(new Runnable() {
@Override
public void run() {
if(!timeOutTask.isCanceled()) {
timeOutTask.error(new ErrorBundle(e));
timeOutTask.setCanceled(true);
}
}
});
}
}
});
}
public static Task runnableToTask(final Runnable runnable) {
return new Task() {
@Override
public Object doInBackground() throws Exception {
runnable.run();
return null;
}
};
}
/*
** 按需实现相应的接口
**/
public static abstract class Task<R> implements Runnable {
public abstract R doInBackground() throws Exception;
private boolean mCanceled;
public void setCanceled(boolean canceled) {
this.mCanceled = canceled;
}
public boolean isCanceled() {
return mCanceled;
}
public void success(R result) {
}
public void error(ErrorBundle errorBundle){
}
@Override
public void run() {
final R result;
try {
result = doInBackground();
runOnUIThread(new Runnable() {
@Override
public void run() {
if(!isCanceled()){
success(result);
}
}
});
} catch (final Exception e) {
runOnUIThread(new Runnable() {
@Override
public void run() {
error(new ErrorBundle(e));
}
});
}
}
}
/**
* 在一个特定的后台线程执行任务,可认为是有序的
* @param runnable
*/
public static void runOnBackgroundThread(Runnable runnable) {
sBackgroundHandler.postDelayed(runnable,0);
}
public static void runOnBackgroundThread(Runnable runnable,long delayed) {
sBackgroundHandler.postDelayed(runnable,delayed);
}
public static void removeBackgroundCallback(Runnable runnable) {
sBackgroundHandler.removeCallbacks(runnable);
}
public static void runOnUIThread(Runnable runnable) {
if(isMainThread()) {
runnable.run();
}else {
sMainHandler.post(runnable);
}
}
public static void removeUICallback(Runnable runnable) {
sMainHandler.removeCallbacks(runnable);
}
public static ExecutorService getExecutor() {
return mParallelExecutor;
}
public static <R > void notifySuccessToUI(final R response, final TaskCallback.Callback<R> taskCallback) {
runOnUIThread(new Runnable() {
@Override
public void run() {
taskCallback.onSuccess(response);
}
});
}
public static <R > void notifyErrorToUI(final ErrorBundle error, final TaskCallback.Callback<R> taskCallback) {
runOnUIThread(new Runnable() {
@Override
public void run() {
taskCallback.onError(error);
}
});
}
public static boolean isMainThread() {
return Thread.currentThread()== sMainHandler.getLooper().getThread();
}
private static final ThreadFactory sTimeOutThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(@NonNull Runnable r) {
Thread thread = new Thread(r, "werewolf timeoutThread #" + mCount.getAndIncrement());
thread.setPriority(Process.THREAD_PRIORITY_BACKGROUND);
return thread;
}
};
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(@NonNull Runnable r) {
Thread thread = new Thread(r, "werewolf thread #" + mCount.getAndIncrement());
thread.setPriority(Process.THREAD_PRIORITY_BACKGROUND);
return thread;
}
};
}