diff --git a/app/build.gradle b/app/build.gradle index 80ab575..571a618 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,7 +25,7 @@ dependencies { exclude group: 'com.android.support', module: 'support-annotations' }) -// compile project(':easythread') - compile 'com.github.yjfnypeu:EasyThread:0.2.0' + compile project(':easythread') +// compile 'com.github.yjfnypeu:EasyThread:0.2.0' testCompile 'junit:junit:4.12' } diff --git a/app/src/main/java/com/lzh/easythreadmanager/sample/MainActivity.java b/app/src/main/java/com/lzh/easythreadmanager/sample/MainActivity.java index ab6b139..d0b9af9 100644 --- a/app/src/main/java/com/lzh/easythreadmanager/sample/MainActivity.java +++ b/app/src/main/java/com/lzh/easythreadmanager/sample/MainActivity.java @@ -2,11 +2,13 @@ import android.app.Activity; import android.os.Bundle; +import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.Toast; +import com.lzh.easythread.AsyncCallback; import com.lzh.easythread.EasyThread; import com.lzh.easythread.Callback; @@ -29,15 +31,13 @@ protected void onCreate(Bundle savedInstanceState) { executor = EasyThread.Builder .fixed(2) .priority(Thread.MAX_PRIORITY) - .name("thread name") + .name("default thread name") .build(); } public void onNormalClick (View v) { - - - executor.name(editText.getText().toString()) - .callback(new ThreadCallback()) + resetThreadName(); + executor.callback(new ThreadCallback()) .execute(new Runnable() { @Override public void run() { @@ -45,9 +45,22 @@ public void run() { } }); - Future submit = executor.name("test submit") + AsyncCallback async = new AsyncCallback() { + @Override + public void onSuccess(User user) { + System.out.println("user = [" + user + "]"); + } + + @Override + public void onFailed(Throwable t) { + System.out.println("t = [" + t + "]"); + } + }; + + executor.name("test submit") .callback(new ThreadCallback()) - .submit(new Callable() { + // 使用异步任务 + .async(new Callable() { @Override public User call() throws Exception { User user = new User(); @@ -55,18 +68,12 @@ public User call() throws Exception { user.password = "123456"; return user; } - }); - try { - User user = submit.get(1, TimeUnit.SECONDS); - System.out.println(user); - } catch (Throwable e) { - e.printStackTrace(); - } + }, async); } public void onExceptionClick (View v) { - executor.name(editText.getText().toString()) - .callback(new ThreadCallback()) + resetThreadName(); + executor.callback(new ThreadCallback()) .execute(new Runnable() { @Override public void run() { @@ -92,4 +99,11 @@ public void onStart(Thread thread) { } } + + private void resetThreadName() { + String name = editText.getText().toString(); + if (!TextUtils.isEmpty(name)) { + executor.name(name); + } + } } diff --git a/easythread/src/main/java/com/lzh/easythread/AndroidMainExecutor.java b/easythread/src/main/java/com/lzh/easythread/AndroidMainExecutor.java new file mode 100644 index 0000000..7b0db3e --- /dev/null +++ b/easythread/src/main/java/com/lzh/easythread/AndroidMainExecutor.java @@ -0,0 +1,31 @@ +package com.lzh.easythread; + +import android.os.Handler; +import android.os.Looper; + +import java.util.concurrent.Executor; + +final class AndroidMainExecutor implements Executor { + + private static AndroidMainExecutor instance = new AndroidMainExecutor(); + private Handler main = new Handler(Looper.getMainLooper()); + + static AndroidMainExecutor getInstance() { + return instance; + } + + @Override + public void execute(final Runnable runnable) { + if (Looper.myLooper() == Looper.getMainLooper()) { + runnable.run(); + return; + } + + main.post(new Runnable() { + @Override + public void run() { + runnable.run(); + } + }); + } +} diff --git a/easythread/src/main/java/com/lzh/easythread/AsyncCallback.java b/easythread/src/main/java/com/lzh/easythread/AsyncCallback.java new file mode 100644 index 0000000..304966f --- /dev/null +++ b/easythread/src/main/java/com/lzh/easythread/AsyncCallback.java @@ -0,0 +1,10 @@ +package com.lzh.easythread; + +/** + * Async callback class. + * @author haoge on 2018/2/9. + */ +public interface AsyncCallback { + void onSuccess(T t); + void onFailed(Throwable t); +} diff --git a/easythread/src/main/java/com/lzh/easythread/CallableWrapper.java b/easythread/src/main/java/com/lzh/easythread/CallableWrapper.java index ae5e7b0..579eff6 100644 --- a/easythread/src/main/java/com/lzh/easythread/CallableWrapper.java +++ b/easythread/src/main/java/com/lzh/easythread/CallableWrapper.java @@ -16,9 +16,7 @@ package com.lzh.easythread; import java.util.concurrent.Callable; -/** - * A Callable Wrapper to delegate {@link Callable#call()} - */ + final class CallableWrapper implements Callable { private String name; private Callback callback; diff --git a/easythread/src/main/java/com/lzh/easythread/CallbackDelegate.java b/easythread/src/main/java/com/lzh/easythread/CallbackDelegate.java new file mode 100644 index 0000000..672a866 --- /dev/null +++ b/easythread/src/main/java/com/lzh/easythread/CallbackDelegate.java @@ -0,0 +1,83 @@ +package com.lzh.easythread; + +import java.util.concurrent.Executor; + +/** + * The callback delegate class. + * + * @author haoge on 2018/2/9. + */ +final class CallbackDelegate implements Callback, AsyncCallback { + + private Callback callback; + private AsyncCallback async; + private Executor deliver; + + CallbackDelegate(Callback callback, Executor deliver, AsyncCallback async) { + this.callback = callback; + this.deliver = deliver; + this.async = async; + } + + @Override + public void onSuccess(final Object o) { + if (async == null) return; + deliver.execute(new Runnable() { + @Override + public void run() { + try { + //noinspection unchecked + async.onSuccess(o); + } catch (Throwable t) { + onFailed(t); + } + } + }); + } + + @Override + public void onFailed(final Throwable t) { + if (async == null) return; + deliver.execute(new Runnable() { + @Override + public void run() { + async.onFailed(t); + } + }); + } + + @Override + public void onError(final Thread thread, final Throwable t) { + onFailed(t); + + if (callback == null) return; + deliver.execute(new Runnable() { + @Override + public void run() { + callback.onError(thread, t); + } + }); + } + + @Override + public void onCompleted(final Thread thread) { + if (callback == null) return; + deliver.execute(new Runnable() { + @Override + public void run() { + callback.onCompleted(thread); + } + }); + } + + @Override + public void onStart(final Thread thread) { + if (callback == null) return; + deliver.execute(new Runnable() { + @Override + public void run() { + callback.onStart(thread); + } + }); + } +} diff --git a/easythread/src/main/java/com/lzh/easythread/EasyThread.java b/easythread/src/main/java/com/lzh/easythread/EasyThread.java index 38a269d..dfbde68 100644 --- a/easythread/src/main/java/com/lzh/easythread/EasyThread.java +++ b/easythread/src/main/java/com/lzh/easythread/EasyThread.java @@ -15,9 +15,6 @@ */ package com.lzh.easythread; -import android.os.Handler; -import android.os.Looper; - import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; @@ -29,72 +26,140 @@ public final class EasyThread implements Executor{ private ExecutorService pool; - private String defName;// default thread name. - private Callback defCallback;// default thread callback. - - private String name;// a temp thread name. just used for current task. - private Callback callback;// a temp thread callback. just used for current task. - private long delay;// the delay time for current task. only the task is created with type of scheduled. it will be worked. - - private EasyThread(int type, int size, int priority, String name, Callback callback) { + // ==== There are default configs + private String defName;// default thread name + private Callback defCallback;// default thread callback + private Executor defDeliver;// default thread deliver + + // ==== There are temp configs(once) + private String name;// thread name + private Callback callback;// thread callback + private long delay;// delay time + private Executor deliver;// thread deliver + + private EasyThread(int type, int size, int priority, String name, Callback callback, Executor deliver) { this.pool = createPool(type, size, priority); this.defName = name; this.defCallback = callback; + this.defDeliver = deliver; } + /** + * Set thread name for current task. if not set. the default name should be used. + * @param name thread name + * @return EasyThread + */ public EasyThread name (String name) { this.name = name; return this; } + /** + * Set thread callback for current task, if not set, the default callback should be used. + * @param callback thread callback + * @return EasyThread + */ public EasyThread callback (Callback callback) { this.callback = callback; return this; } + /** + * Set the delay time for current task. + * + *

Attention: it only take effects when your thread pool is create by {@link Builder#scheduled(int)}

+ * @param time time length + * @param unit time unit + * @return EasyThread + */ public EasyThread delay (long time, TimeUnit unit) { delay = unit.toMillis(time); return this; } + /** + * Set the thread deliver for current task. if not set, the default deliver should be used. + * @param deliver thread deliver + * @return EasyThread + */ + public EasyThread deliver(Executor deliver){ + this.deliver = deliver; + return this; + } + + /** + * Launch task + * @param runnable task + */ @Override public void execute (Runnable runnable) { + runnable = new RunnableWrapper(getName(), getCallback(null)).setRunnable(runnable); if (delay > 0 && pool instanceof ScheduledExecutorService) { ((ScheduledExecutorService)pool).schedule(runnable, delay, TimeUnit.MILLISECONDS); } else { - pool.execute(new RunnableWrapper(getName(), getCallback(), runnable)); + pool.execute(runnable); } release(); } + /** + * Launch async task, and the callback are used for receive the result of callable task. + * @param callable callable + * @param callback callback + * @param type + */ + public void async(Callable callable, AsyncCallback callback) { + Runnable runnable = new RunnableWrapper(getName(), getCallback(callback)) + .setCallable(callable); + if (delay > 0 && pool instanceof ScheduledExecutorService) { + ((ScheduledExecutorService)pool).schedule(runnable, delay, TimeUnit.MILLISECONDS); + } else { + pool.execute(runnable); + } + release(); + } + + /** + * Launch task + * @param callable callable + * @param type + * @return {@link Future} + */ public Future submit (Callable callable) { Future result; + callable = new CallableWrapper<>(getName() ,getCallback(null),callable); if (delay > 0 && pool instanceof ScheduledExecutorService) { result = ((ScheduledExecutorService)pool).schedule(callable, delay, TimeUnit.MILLISECONDS); } else { - result = pool.submit(new CallableWrapper<>(getName() ,getCallback(),callable)); + result = pool.submit(callable); } release(); return result; } + /** + * get thread pool that be created. + * @return thread pool + */ + public ExecutorService getExecutor() { + return pool; + } + private void release() { this.name = null; this.callback = null; this.delay = -1; + this.deliver = null; } private String getName () { return Tools.isEmpty(name) ? defName : name; } - private Callback getCallback () { - Callback used = callback == null ? defCallback : callback; - if (Tools.isAndroid) { - return new AndroidCallback(used); - } else { - return used; - } + private CallbackDelegate getCallback (AsyncCallback async) { + Callback used = this.callback == null ? defCallback : callback; + Executor deliver = this.deliver == null ? defDeliver : this.deliver; + return new CallbackDelegate(used, deliver, async); } private ExecutorService createPool(int type, int size, int priority) { @@ -126,51 +191,6 @@ public Thread newThread(Runnable runnable) { } } - private static class AndroidCallback implements Callback { - private static Handler main = new Handler(Looper.getMainLooper()); - private Callback delegate; - - AndroidCallback(Callback delegate) { - this.delegate = delegate; - } - - @Override - public void onError(final Thread thread, final Throwable t) { - main.post(new Runnable() { - @Override - public void run() { - if (delegate != null) { - delegate.onError(thread, t); - } - } - }); - } - - @Override - public void onCompleted(final Thread thread) { - main.post(new Runnable() { - @Override - public void run() { - if (delegate != null) { - delegate.onCompleted(thread); - } - } - }); - } - - @Override - public void onStart(final Thread thread) { - main.post(new Runnable() { - @Override - public void run() { - if (delegate != null) { - delegate.onStart(thread); - } - } - }); - } - } - public static class Builder { final static int TYPE_CACHEABLE = 0; final static int TYPE_FIXED = 1; @@ -182,14 +202,15 @@ public static class Builder { int priority = Thread.NORM_PRIORITY; String name; Callback callback; + Executor deliver; private Builder(int size, int type) { - this.size = size; + this.size = Math.max(1, size); this.type = type; } /** - * Create a cacheable thread manager to used:Executors.newCachedThreadPool() + * Create thread pool by Executors.newCachedThreadPool() * @return Builder itself */ public static Builder cacheable () { @@ -197,8 +218,8 @@ public static Builder cacheable () { } /** - * Create a thread manager with a limit size to used:Executors.newFixedThreadPool() - * @param size size + * Create thread pool by Executors.newFixedThreadPool() + * @param size thread size * @return Builder itself */ public static Builder fixed (int size) { @@ -206,8 +227,8 @@ public static Builder fixed (int size) { } /** - * Create a thread manager with a scheduled thread pool: Executors.newScheduledThreadPool() - * @param size Thread size. + * Create thread pool by Executors.newScheduledThreadPool() + * @param size thread size * @return Builder itself */ public static Builder scheduled (int size) { @@ -215,7 +236,7 @@ public static Builder scheduled (int size) { } /** - * create a thread manager with single thread to used + * Create thread pool by Executors.newSingleThreadPool() * * @return Builder itself */ @@ -224,8 +245,8 @@ public static Builder single () { } /** - * Set a default name for thread manager to used - * @param name The thread name. + * Set default thread name to used. + * @param name default thread name * @return Builder itself */ public Builder name (String name) { @@ -236,8 +257,8 @@ public Builder name (String name) { } /** - * Set a default priority for thread manager to used - * @param priority The thread priority + * Set default thread priority to used. + * @param priority thread priority * @return itself */ public Builder priority (int priority) { @@ -246,15 +267,25 @@ public Builder priority (int priority) { } /** - * Set a default callback for thread manager - * @param callback The callback - * @return itself + * Set default thread callback to used. + * @param callback thread callback + * @return itself */ public Builder callback (Callback callback) { this.callback = callback; return this; } + /** + * Set default thread deliver to used. + * @param deliver default thread deliver + * @return itself + */ + public Builder deliver (Executor deliver) { + this.deliver = deliver; + return this; + } + /** * Create a thread manager to used with some configurations. * @return EasyThread instance @@ -279,7 +310,15 @@ public EasyThread build () { } } - return new EasyThread(type,size,priority,name,callback); + if (deliver == null) { + if (Tools.isAndroid) { + deliver = AndroidMainExecutor.getInstance(); + } else { + deliver = NotSwitchExecutor.getInstance(); + } + } + + return new EasyThread(type, size, priority, name, callback, deliver); } } } diff --git a/easythread/src/main/java/com/lzh/easythread/NotSwitchExecutor.java b/easythread/src/main/java/com/lzh/easythread/NotSwitchExecutor.java new file mode 100644 index 0000000..4352930 --- /dev/null +++ b/easythread/src/main/java/com/lzh/easythread/NotSwitchExecutor.java @@ -0,0 +1,17 @@ +package com.lzh.easythread; + +import java.util.concurrent.Executor; + +final class NotSwitchExecutor implements Executor { + + private static NotSwitchExecutor instance = new NotSwitchExecutor(); + + static NotSwitchExecutor getInstance() { + return instance; + } + + @Override + public void execute(Runnable runnable) { + runnable.run(); + } +} diff --git a/easythread/src/main/java/com/lzh/easythread/RunnableWrapper.java b/easythread/src/main/java/com/lzh/easythread/RunnableWrapper.java index 1c3ab68..1250e3b 100644 --- a/easythread/src/main/java/com/lzh/easythread/RunnableWrapper.java +++ b/easythread/src/main/java/com/lzh/easythread/RunnableWrapper.java @@ -15,33 +15,47 @@ */ package com.lzh.easythread; -/** - * A Runnable Wrapper to delegate {@link Runnable#run()} - */ +import java.util.concurrent.Callable; + final class RunnableWrapper implements Runnable { private String name; - private Callback callback; - private Runnable proxy; + private CallbackDelegate delegate; + private Runnable runnable; + private Callable callable; - RunnableWrapper(String name, Callback callback, Runnable proxy) { + RunnableWrapper(String name, CallbackDelegate callback) { this.name = name; - this.callback = callback; - this.proxy = proxy; + this.delegate = callback; + } + + RunnableWrapper setRunnable(Runnable runnable) { + this.runnable = runnable; + return this; + } + + RunnableWrapper setCallable(Callable callable) { + this.callable = callable; + return this; } @Override public void run() { - Tools.resetThread(Thread.currentThread(),name,callback); - if (callback != null) { - callback.onStart(Thread.currentThread()); - } + Thread current = Thread.currentThread(); + Tools.resetThread(current, name, delegate); + delegate.onStart(current); + // avoid NullPointException - if (proxy != null) { - proxy.run(); - } - if (callback != null) { - callback.onCompleted(Thread.currentThread()); + if (runnable != null) { + runnable.run(); + } else if (callable != null) { + try { + Object result = callable.call(); + delegate.onSuccess(result); + } catch (Exception e) { + delegate.onError(current, e); + } } + delegate.onCompleted(current); } } diff --git a/easythread/src/main/java/com/lzh/easythread/Tools.java b/easythread/src/main/java/com/lzh/easythread/Tools.java index 5a38fb4..f25eb4c 100644 --- a/easythread/src/main/java/com/lzh/easythread/Tools.java +++ b/easythread/src/main/java/com/lzh/easythread/Tools.java @@ -17,7 +17,7 @@ final class Tools { - static boolean isAndroid; + static boolean isAndroid;// Flag: is on android platform /** * Reset thread name and set a UnCaughtExceptionHandler to wrap callback to notify user when occurs a exception diff --git a/javatest/src/main/java/com/example/EasyThreadTest.java b/javatest/src/main/java/com/example/EasyThreadTest.java index e48307c..2ead519 100644 --- a/javatest/src/main/java/com/example/EasyThreadTest.java +++ b/javatest/src/main/java/com/example/EasyThreadTest.java @@ -1,5 +1,6 @@ package com.example; +import com.lzh.easythread.AsyncCallback; import com.lzh.easythread.Callback; import com.lzh.easythread.EasyThread; @@ -60,5 +61,22 @@ public Integer call() throws Exception { } System.out.println("result = " + result); + + easyThread.async(new Callable() { + @Override + public String call() throws Exception { + return "async task result"; + } + }, new AsyncCallback() { + @Override + public void onSuccess(String response) { + System.out.println("response = [" + response + "]"); + } + + @Override + public void onFailed(Throwable t) { + System.out.println("t = [" + t + "]"); + } + }); } } \ No newline at end of file