add async package

This commit is contained in:
pengfei.zhou 2019-07-19 14:58:05 +08:00
parent 920aab1035
commit 3055beb744
7 changed files with 167 additions and 46 deletions

View File

@ -1,8 +1,9 @@
package com.github.pengfeizhou.doric;
import com.github.pengfeizhou.doric.async.AsyncResult;
import com.github.pengfeizhou.doric.bridge.DoricNativePlugin;
import com.github.pengfeizhou.doric.extension.DoricPluginInfo;
import com.github.pengfeizhou.doric.utils.DoricSettableFuture;
import com.github.pengfeizhou.doric.async.SettableFuture;
import com.github.pengfeizhou.jscore.JSDecoder;
import java.util.HashMap;
@ -25,7 +26,7 @@ public class DoricContext {
return DoricDriver.getInstance().createContext(script, alias);
}
public DoricSettableFuture<JSDecoder> callEntity(String methodName, Object... args) {
public AsyncResult<JSDecoder> callEntity(String methodName, Object... args) {
return DoricDriver.getInstance().invokeContextMethod(mContextId, methodName, args);
}

View File

@ -1,7 +1,7 @@
package com.github.pengfeizhou.doric;
import com.github.pengfeizhou.doric.async.AsyncResult;
import com.github.pengfeizhou.doric.engine.DoricJSEngine;
import com.github.pengfeizhou.doric.utils.DoricSettableFuture;
import com.github.pengfeizhou.jscore.JSDecoder;
import java.util.Map;
@ -18,7 +18,7 @@ public class DoricDriver {
private final AtomicInteger counter = new AtomicInteger();
private final Map<String, DoricContext> doricContextMap = new ConcurrentHashMap<>();
public DoricSettableFuture<JSDecoder> invokeContextMethod(final String contextId, final String method, final Object... args) {
public AsyncResult<JSDecoder> invokeContextMethod(final String contextId, final String method, final Object... args) {
return doricJSEngine.invokeContextEntityMethod(contextId, method, args);
}
@ -36,15 +36,27 @@ public class DoricDriver {
DoricContext createContext(final String script, final String source) {
String contextId = String.valueOf(counter.incrementAndGet());
doricJSEngine.prepareContext(contextId, script, source);
DoricContext doricContext = new DoricContext(contextId);
doricJSEngine.prepareContext(contextId, script, source);
doricContextMap.put(contextId, doricContext);
return doricContext;
}
void destroyContext(String contextId) {
doricContextMap.remove(contextId);
doricJSEngine.destroyContext(contextId);
void destroyContext(final String contextId) {
doricJSEngine.destroyContext(contextId).setCallback(new AsyncResult.Callback<Boolean>() {
@Override
public void onResult(Boolean result) {
}
@Override
public void onError(Throwable t) {
}
@Override
public void onFinish() {
doricContextMap.remove(contextId);
}
});
}
public DoricContext getContext(String contextId) {

View File

@ -0,0 +1,37 @@
package com.github.pengfeizhou.doric.async;
import android.os.Handler;
import android.os.Looper;
import java.util.concurrent.Callable;
/**
* @Description: com.github.pengfeizhou.doric.async
* @Author: pengfei.zhou
* @CreateDate: 2019-07-19
*/
public class AsyncCall {
public static <T> AsyncResult<T> ensureRunInHandler(Handler handler, final Callable<T> callable) {
final AsyncResult<T> asyncResult = new AsyncResult<>();
if (Looper.myLooper() == handler.getLooper()) {
try {
asyncResult.setResult(callable.call());
} catch (Exception e) {
asyncResult.setError(e);
}
} else {
handler.post(new Runnable() {
@Override
public void run() {
try {
asyncResult.setResult(callable.call());
} catch (Exception e) {
asyncResult.setError(e);
}
}
});
}
return asyncResult;
}
}

View File

@ -0,0 +1,70 @@
package com.github.pengfeizhou.doric.async;
/**
* @Description: com.github.pengfeizhou.doric.async
* @Author: pengfei.zhou
* @CreateDate: 2019-07-19
*/
public class AsyncResult<R> {
private static Object EMPTY = new Object();
private Object result = EMPTY;
private Callback<R> callback = null;
public void setResult(R result) {
this.result = result;
if (this.callback != null) {
this.callback.onResult(result);
this.callback.onFinish();
}
}
public void setError(Throwable result) {
this.result = result;
if (this.callback != null) {
this.callback.onError(result);
this.callback.onFinish();
}
}
public void setCallback(Callback<R> callback) {
this.callback = callback;
if (result instanceof Throwable) {
this.callback.onError((Throwable) result);
this.callback.onFinish();
} else if (result != EMPTY) {
this.callback.onResult((R) result);
this.callback.onFinish();
}
}
public SettableFuture<R> synchronous() {
final SettableFuture<R> settableFuture = new SettableFuture<>();
setCallback(new Callback<R>() {
@Override
public void onResult(R result) {
settableFuture.set(result);
}
@Override
public void onError(Throwable t) {
settableFuture.set(null);
}
@Override
public void onFinish() {
}
});
return settableFuture;
}
public interface Callback<R> {
void onResult(R result);
void onError(Throwable t);
void onFinish();
}
}

View File

@ -1,7 +1,7 @@
package com.github.pengfeizhou.doric.utils;
package com.github.pengfeizhou.doric.async;
/**
* @Description: Doric
* @Description: com.github.pengfeizhou.doric.async
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
@ -13,7 +13,7 @@ import java.util.concurrent.TimeUnit;
* A super simple Future-like class that can safely notify another Thread when a value is ready.
* Does not support setting errors or canceling.
*/
public class DoricSettableFuture<T> {
public class SettableFuture<T> {
private final CountDownLatch mReadyLatch = new CountDownLatch(1);
private volatile

View File

@ -7,10 +7,12 @@ import android.os.Message;
import android.text.TextUtils;
import com.github.pengfeizhou.doric.Doric;
import com.github.pengfeizhou.doric.async.AsyncCall;
import com.github.pengfeizhou.doric.extension.DoricBridgeExtension;
import com.github.pengfeizhou.doric.async.AsyncResult;
import com.github.pengfeizhou.doric.utils.DoricConstant;
import com.github.pengfeizhou.doric.utils.DoricLog;
import com.github.pengfeizhou.doric.utils.DoricSettableFuture;
import com.github.pengfeizhou.doric.async.SettableFuture;
import com.github.pengfeizhou.doric.extension.DoricTimerExtension;
import com.github.pengfeizhou.doric.utils.DoricUtils;
import com.github.pengfeizhou.jscore.JSDecoder;
@ -18,6 +20,7 @@ import com.github.pengfeizhou.jscore.JavaFunction;
import com.github.pengfeizhou.jscore.JavaValue;
import java.util.ArrayList;
import java.util.concurrent.Callable;
/**
* @Description: Doric
@ -154,32 +157,34 @@ public class DoricJSEngine implements Handler.Callback, DoricTimerExtension.Time
mDoricJSE.loadJS(script, "Assets://" + assetName);
}
public void prepareContext(final String contextId, final String script, final String source) {
Runnable runnable = new Runnable() {
public AsyncResult<Boolean> prepareContext(final String contextId, final String script, final String source) {
return AsyncCall.ensureRunInHandler(mJSHandler, new Callable<Boolean>() {
@Override
public void run() {
mDoricJSE.loadJS(packageContextScript(contextId, script), "Context://" + source);
public Boolean call() throws Exception {
try {
mDoricJSE.loadJS(packageContextScript(contextId, script), "Context://" + source);
return true;
} catch (Exception e) {
DoricLog.e("Prepare Context error:%s", e.getLocalizedMessage());
return false;
}
}
};
doOnJSThread(runnable);
});
}
public void doOnJSThread(Runnable runnable) {
if (isJSThread()) {
runnable.run();
} else {
mJSHandler.post(runnable);
}
}
public void destroyContext(final String contextId) {
Runnable runnable = new Runnable() {
public AsyncResult<Boolean> destroyContext(final String contextId) {
return AsyncCall.ensureRunInHandler(mJSHandler, new Callable<Boolean>() {
@Override
public void run() {
mDoricJSE.loadJS(String.format(DoricConstant.TEMPLATE_CONTEXT_DESTROY, contextId), "_Context://" + contextId);
public Boolean call() throws Exception {
try {
mDoricJSE.loadJS(String.format(DoricConstant.TEMPLATE_CONTEXT_DESTROY, contextId), "_Context://" + contextId);
return true;
} catch (Exception e) {
DoricLog.e("Prepare Context error:%s", e.getLocalizedMessage());
return false;
}
}
};
doOnJSThread(runnable);
});
}
private String packageContextScript(String contextId, String content) {
@ -190,11 +195,7 @@ public class DoricJSEngine implements Handler.Callback, DoricTimerExtension.Time
return String.format(DoricConstant.TEMPLATE_MODULE, moduleName, content);
}
public boolean isJSThread() {
return Looper.myLooper() == mJSHandler.getLooper();
}
public DoricSettableFuture<JSDecoder> invokeContextEntityMethod(final String contextId, final String method, final Object... args) {
public AsyncResult<JSDecoder> invokeContextEntityMethod(final String contextId, final String method, final Object... args) {
final Object[] nArgs = new Object[args.length + 2];
nArgs[0] = contextId;
nArgs[1] = method;
@ -205,21 +206,18 @@ public class DoricJSEngine implements Handler.Callback, DoricTimerExtension.Time
}
public DoricSettableFuture<JSDecoder> invokeDoricMethod(final String method, final Object... args) {
final DoricSettableFuture<JSDecoder> settableFuture = new DoricSettableFuture<>();
Runnable runnable = new Runnable() {
public AsyncResult<JSDecoder> invokeDoricMethod(final String method, final Object... args) {
return AsyncCall.ensureRunInHandler(mJSHandler, new Callable<JSDecoder>() {
@Override
public void run() {
public JSDecoder call() throws Exception {
ArrayList<JavaValue> values = new ArrayList<>();
for (Object arg : args) {
values.add(DoricUtils.toJavaValue(arg));
}
settableFuture.set(mDoricJSE.invokeMethod(DoricConstant.GLOBAL_DORIC, method,
values.toArray(new JavaValue[values.size()]), true));
return mDoricJSE.invokeMethod(DoricConstant.GLOBAL_DORIC, method,
values.toArray(new JavaValue[values.size()]), true);
}
};
doOnJSThread(runnable);
return settableFuture;
});
}
@Override

View File

@ -1,6 +1,8 @@
package com.github.pengfeizhou.doric.utils;
import android.content.res.AssetManager;
import android.os.Handler;
import android.os.Looper;
import com.github.pengfeizhou.doric.Doric;
import com.github.pengfeizhou.jscore.JavaValue;
@ -60,4 +62,5 @@ public class DoricUtils {
return new JavaValue(String.valueOf(arg));
}
}
}