rename hego to doric

This commit is contained in:
pengfei.zhou
2019-07-19 10:27:09 +08:00
parent 6bcc9ffe49
commit 51c8924c2a
48 changed files with 340 additions and 424 deletions

View File

@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.pengfeizhou.doric" />

View File

@@ -0,0 +1,33 @@
package com.github.pengfeizhou.doric;
import android.app.Application;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class Doric {
private static Application sApplication;
public static void init(Application application) {
sApplication = application;
}
public static Application application() {
return sApplication;
}
private static Map<String, String> bundles = new ConcurrentHashMap<>();
public static void registerJSBundle(String name, String bundle) {
bundles.put(name, bundle);
}
public static String getJSBundle(String name) {
return bundles.get(name);
}
}

View File

@@ -0,0 +1,34 @@
package com.github.pengfeizhou.doric;
import com.github.pengfeizhou.doric.utils.DoricSettableFuture;
import com.github.pengfeizhou.jscore.JSDecoder;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class DoricContext {
private static AtomicInteger sCounter = new AtomicInteger();
private final String mContextId;
private DoricContext(String contextId) {
this.mContextId = contextId;
}
public static DoricContext createContext(String script, String alias) {
String contextId = String.valueOf(sCounter.incrementAndGet());
DoricDriver.getInstance().createPage(contextId, script, alias);
return new DoricContext(contextId);
}
public DoricSettableFuture<JSDecoder> callEntity(String methodName, Object... args) {
return DoricDriver.getInstance().invokeContextMethod(mContextId, methodName, args);
}
public void teardown() {
DoricDriver.getInstance().destoryContext(mContextId);
}
}

View File

@@ -0,0 +1,40 @@
package com.github.pengfeizhou.doric;
import com.github.pengfeizhou.doric.engine.DoricJSEngine;
import com.github.pengfeizhou.doric.utils.DoricSettableFuture;
import com.github.pengfeizhou.jscore.JSDecoder;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class DoricDriver {
private final DoricJSEngine doricJSEngine;
public DoricSettableFuture<JSDecoder> invokeContextMethod(final String contextId, final String method, final Object... args) {
return doricJSEngine.invokeContextEntityMethod(contextId, method, args);
}
private static class Inner {
private static final DoricDriver sInstance = new DoricDriver();
}
private DoricDriver() {
doricJSEngine = new DoricJSEngine();
}
public static DoricDriver getInstance() {
return Inner.sInstance;
}
public void createPage(final String contextId, final String script, final String source) {
doricJSEngine.prepareContext(contextId, script, source);
}
public void destoryContext(String contextId) {
doricJSEngine.destroyContext(contextId);
}
}

View File

@@ -0,0 +1,54 @@
package com.github.pengfeizhou.doric;
import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.widget.FrameLayout;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class DoricPanel extends FrameLayout {
private DoricContext mDoricContext;
public DoricPanel(@NonNull Context context) {
super(context);
}
public DoricPanel(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public DoricPanel(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public DoricPanel(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public void config(String script, String alias) {
DoricContext doricContext = DoricContext.createContext(script, alias);
config(doricContext);
}
public void config(DoricContext doricContext) {
mDoricContext = doricContext;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
}
public DoricContext getDoricContext() {
return mDoricContext;
}
}

View File

@@ -0,0 +1,18 @@
package com.github.pengfeizhou.doric.bridge;
import com.github.pengfeizhou.doric.DoricContext;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public abstract class BaseModule {
private final DoricContext doricContext;
protected BaseModule(DoricContext doricContext) {
this.doricContext = doricContext;
}
public abstract String moduleName();
}

View File

@@ -0,0 +1,26 @@
package com.github.pengfeizhou.doric.bridge;
import com.github.pengfeizhou.doric.DoricContext;
import com.github.pengfeizhou.doric.extension.DoricMethod;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class ModalModule extends BaseModule {
protected ModalModule(DoricContext doricContext) {
super(doricContext);
}
@Override
public String moduleName() {
return "modal";
}
@DoricMethod(name = "toast")
public void toast() {
}
}

View File

@@ -0,0 +1,249 @@
package com.github.pengfeizhou.doric.engine;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import com.github.pengfeizhou.doric.Doric;
import com.github.pengfeizhou.doric.extension.DoricBridgeExtension;
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.extension.DoricTimerExtension;
import com.github.pengfeizhou.doric.utils.DoricUtils;
import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JavaFunction;
import com.github.pengfeizhou.jscore.JavaValue;
import org.json.JSONObject;
import java.util.ArrayList;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class DoricJSEngine implements Handler.Callback, DoricTimerExtension.TimerCallback {
private final Handler mJSHandler;
private final DoricBridgeExtension mDoricBridgeExtension;
private IDoricJSE mDoricJSE;
private DoricTimerExtension mTimerExtension;
public DoricJSEngine() {
HandlerThread handlerThread = new HandlerThread(this.getClass().getSimpleName());
handlerThread.start();
Looper looper = handlerThread.getLooper();
mJSHandler = new Handler(looper, this);
mJSHandler.post(new Runnable() {
@Override
public void run() {
initJSExecutor();
initHugoRuntime();
}
});
mTimerExtension = new DoricTimerExtension(looper, this);
mDoricBridgeExtension = new DoricBridgeExtension();
}
private void initJSExecutor() {
mDoricJSE = new DoricJSExecutor();
mDoricJSE.injectGlobalJSFunction(DoricConstant.INJECT_LOG, new JavaFunction() {
@Override
public JavaValue exec(JSDecoder[] args) {
try {
String type = args[0].string();
String message = args[1].string();
switch (type) {
case "w":
DoricLog.w(message, "_js");
break;
case "e":
DoricLog.e(message, "_js");
break;
default:
DoricLog.d(message, "_js");
break;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
mDoricJSE.injectGlobalJSFunction(DoricConstant.INJECT_REQUIRE, new JavaFunction() {
@Override
public JavaValue exec(JSDecoder[] args) {
try {
String name = args[0].string();
String content = Doric.getJSBundle(name);
if (TextUtils.isEmpty(content)) {
DoricLog.e("error");
return new JavaValue(false);
}
mDoricJSE.loadJS(packageModuleScript(name, content), "Module://" + name);
return new JavaValue(true);
} catch (Exception e) {
e.printStackTrace();
return new JavaValue(false);
}
}
});
mDoricJSE.injectGlobalJSFunction(DoricConstant.INJECT_TIMER_SET, new JavaFunction() {
@Override
public JavaValue exec(JSDecoder[] args) {
try {
mTimerExtension.setTimer(
args[0].number().longValue(),
args[1].number().longValue(),
args[2].bool());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
mDoricJSE.injectGlobalJSFunction(DoricConstant.INJECT_TIMER_CLEAR, new JavaFunction() {
@Override
public JavaValue exec(JSDecoder[] args) {
try {
mTimerExtension.clearTimer(args[0].number().longValue());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
mDoricJSE.injectGlobalJSFunction(DoricConstant.INJECT_BRIDGE, new JavaFunction() {
@Override
public JavaValue exec(JSDecoder[] args) {
try {
String contextId = args[0].string();
String module = args[1].string();
String method = args[2].string();
String callbackId = args[3].string();
JSDecoder jsDecoder = args[4];
return mDoricBridgeExtension.callNative(contextId, module, method, callbackId, jsDecoder);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
}
private void initHugoRuntime() {
loadBuiltinJS(DoricConstant.DORIC_BUNDLE_SANDBOX);
String libName = DoricConstant.DORIC_MODULE_LIB;
String libJS = DoricUtils.readAssetFile(DoricConstant.DORIC_BUNDLE_LIB);
mDoricJSE.loadJS(packageModuleScript(libName, libJS), "Module://" + libName);
}
@Override
public boolean handleMessage(Message msg) {
return false;
}
public void teardown() {
mDoricJSE.teardown();
}
private void loadBuiltinJS(String assetName) {
String script = DoricUtils.readAssetFile(assetName);
mDoricJSE.loadJS(script, "Assets://" + assetName);
}
public void prepareContext(final String contextId, final String script, final String source) {
Runnable runnable = new Runnable() {
@Override
public void run() {
mDoricJSE.loadJS(packageContextScript(contextId, script), "Context://" + source);
}
};
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() {
@Override
public void run() {
mDoricJSE.loadJS(String.format(DoricConstant.TEMPLATE_CONTEXT_DESTROY, contextId), "_Context://" + contextId);
}
};
doOnJSThread(runnable);
}
private String packageContextScript(String contextId, String content) {
return String.format(DoricConstant.TEMPLATE_CONTEXT_CREATE, content, contextId, contextId);
}
private String packageModuleScript(String moduleName, String content) {
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) {
final Object[] nArgs = new Object[args.length + 2];
nArgs[0] = contextId;
nArgs[1] = method;
if (args.length > 0) {
System.arraycopy(args, 0, nArgs, 2, args.length);
}
return invokeDoricMethod(DoricConstant.DORIC_CONTEXT_INVOKE, nArgs);
}
public DoricSettableFuture<JSDecoder> invokeDoricMethod(final String method, final Object... args) {
final DoricSettableFuture<JSDecoder> settableFuture = new DoricSettableFuture<>();
Runnable runnable = new Runnable() {
@Override
public void run() {
ArrayList<JavaValue> values = new ArrayList<>();
for (Object arg : args) {
if (arg == null) {
values.add(new JavaValue());
} else if (arg instanceof JSONObject) {
values.add(new JavaValue((JSONObject) arg));
} else if (arg instanceof String) {
values.add(new JavaValue((String) arg));
} else if (arg instanceof Integer) {
values.add(new JavaValue((Integer) arg));
} else if (arg instanceof Long) {
values.add(new JavaValue((Long) arg));
} else if (arg instanceof Double) {
values.add(new JavaValue((Double) arg));
} else if (arg instanceof Boolean) {
values.add(new JavaValue((Boolean) arg));
} else if (arg instanceof JavaValue) {
values.add((JavaValue) arg);
} else {
values.add(new JavaValue(String.valueOf(arg)));
}
}
settableFuture.set(mDoricJSE.invokeMethod(DoricConstant.GLOBAL_DORIC, method,
values.toArray(new JavaValue[values.size()]), true));
}
};
doOnJSThread(runnable);
return settableFuture;
}
@Override
public void callback(long timerId) {
invokeDoricMethod(DoricConstant.DORIC_TIMER_CALLBACK, timerId);
}
}

View File

@@ -0,0 +1,51 @@
package com.github.pengfeizhou.doric.engine;
import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JSExecutor;
import com.github.pengfeizhou.jscore.JSRuntimeException;
import com.github.pengfeizhou.jscore.JavaFunction;
import com.github.pengfeizhou.jscore.JavaValue;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class DoricJSExecutor implements IDoricJSE {
private final JSExecutor mJSExecutor;
public DoricJSExecutor() {
this.mJSExecutor = JSExecutor.create();
}
@Override
public String loadJS(String script, String source) throws JSRuntimeException {
return mJSExecutor.loadJS(script, source);
}
@Override
public JSDecoder evaluateJS(String script, String source, boolean hashKey) throws JSRuntimeException {
return mJSExecutor.evaluateJS(script, source, hashKey);
}
@Override
public void injectGlobalJSFunction(String name, JavaFunction javaFunction) {
mJSExecutor.injectGlobalJSFunction(name, javaFunction);
}
@Override
public void injectGlobalJSObject(String name, JavaValue javaValue) {
mJSExecutor.injectGlobalJSObject(name, javaValue);
}
@Override
public JSDecoder invokeMethod(String objectName, String functionName, JavaValue[] javaValues, boolean hashKey) throws JSRuntimeException {
return mJSExecutor.invokeMethod(objectName, functionName, javaValues, hashKey);
}
@Override
public void teardown() {
mJSExecutor.destroy();
}
}

View File

@@ -0,0 +1,64 @@
package com.github.pengfeizhou.doric.engine;
import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JSRuntimeException;
import com.github.pengfeizhou.jscore.JavaFunction;
import com.github.pengfeizhou.jscore.JavaValue;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public interface IDoricJSE {
/**
* 执行JS语句
*
* @param script 执行的JS语句
* @param source 该JS语句对应的文件名在输出错误的堆栈信息时有用
* @return 返回JS语句的执行结果以String形式返回
* @throws JSRuntimeException 如果执行的脚本有异常会抛出包含堆栈的JSRuntimeException
*/
String loadJS(String script, String source) throws JSRuntimeException;
/**
* 执行JS语句
*
* @param script 执行的JS语句
* @param source 该JS语句对应的文件名在输出错误的堆栈信息时有用
* @param hashKey 是否在返回对象序列化时将key hash化
* @return 返回JS语句的执行结果以二进制数据的形式返回
* @throws JSRuntimeException 如果执行的脚本有异常会抛出包含堆栈的JSRuntimeException
*/
JSDecoder evaluateJS(String script, String source, boolean hashKey) throws JSRuntimeException;
/**
* 向JS注入全局方法由java实现
*
* @param name js的方法名
* @param javaFunction java中对应的实现类
*/
void injectGlobalJSFunction(String name, JavaFunction javaFunction);
/**
* 向JS注入全局变量
*
* @param name js中的变量名
* @param javaValue 注入的全局变量按Value进行组装
*/
void injectGlobalJSObject(String name, JavaValue javaValue);
/**
* 执行JS某个方法
*
* @param objectName 执行的方法所属的变量名如果方法为全局方法该参数传null
* @param functionName 执行的方法名
* @param javaValues 方法需要的参数列表,按数组传入
* @param hashKey 是否在返回对象序列化时将key hash化
* @throws JSRuntimeException 如果执行的方法有异常会抛出包含堆栈的JSRuntimeException
*/
JSDecoder invokeMethod(String objectName, String functionName, JavaValue[] javaValues, boolean hashKey) throws JSRuntimeException;
void teardown();
}

View File

@@ -0,0 +1,20 @@
package com.github.pengfeizhou.doric.extension;
import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JavaValue;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class DoricBridgeExtension {
public DoricBridgeExtension() {
}
public JavaValue callNative(String contextId, String module, String method, String callbackId, JSDecoder jsDecoder) {
return null;
}
}

View File

@@ -0,0 +1,19 @@
package com.github.pengfeizhou.doric.extension;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DoricMethod {
String name() default "";
}

View File

@@ -0,0 +1,19 @@
package com.github.pengfeizhou.doric.extension;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DoricModule {
String name() default "";
}

View File

@@ -0,0 +1,66 @@
package com.github.pengfeizhou.doric.extension;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import java.util.HashSet;
import java.util.Set;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class DoricTimerExtension implements Handler.Callback {
private static final int MSG_TIMER = 0;
private final Handler mTimerHandler;
private final TimerCallback mTimerCallback;
private Set<Long> mDeletedTimerIds = new HashSet<>();
public DoricTimerExtension(Looper looper, TimerCallback timerCallback) {
mTimerHandler = new Handler(looper, this);
mTimerCallback = timerCallback;
}
public void setTimer(long timerId, long time, boolean repeat) {
TimerInfo timerInfo = new TimerInfo();
timerInfo.timerId = timerId;
timerInfo.time = time;
timerInfo.repeat = repeat;
mTimerHandler.sendMessageDelayed(Message.obtain(mTimerHandler, MSG_TIMER, timerInfo), timerInfo.time);
}
public void clearTimer(long timerId) {
mDeletedTimerIds.add(timerId);
}
@Override
public boolean handleMessage(Message msg) {
if (msg.obj instanceof TimerInfo) {
TimerInfo timerInfo = (TimerInfo) msg.obj;
if (mDeletedTimerIds.contains(timerInfo.timerId)) {
mDeletedTimerIds.remove(timerInfo.timerId);
} else {
mTimerCallback.callback(timerInfo.timerId);
if (timerInfo.repeat) {
mTimerHandler.sendMessageDelayed(Message.obtain(mTimerHandler, MSG_TIMER, timerInfo), timerInfo.time);
} else {
mDeletedTimerIds.remove(timerInfo.timerId);
}
}
}
return true;
}
private class TimerInfo {
long timerId;
long time;
boolean repeat;
}
public interface TimerCallback {
void callback(long timerId);
}
}

View File

@@ -0,0 +1,44 @@
package com.github.pengfeizhou.doric.extension;
import android.text.TextUtils;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class ModuleClassInfo {
private Class clz;
private Object instance;
private Map<String, Method> methodMap = new HashMap<>();
public boolean stringify = false;
public ModuleClassInfo(Class clz) {
this.clz = clz;
try {
this.instance = clz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
Method[] methods = clz.getMethods();
if (methods != null) {
for (Method method : methods) {
DoricMethod doricMethod = method.getAnnotation(DoricMethod.class);
if (doricMethod != null) {
if (TextUtils.isEmpty(doricMethod.name())) {
methodMap.put(method.getName(), method);
} else {
methodMap.put(doricMethod.name(), method);
}
}
}
}
}
}

View File

@@ -0,0 +1,45 @@
package com.github.pengfeizhou.doric.utils;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class DoricConstant {
public static final String DORIC_BUNDLE_SANDBOX = "doric-sandbox.js";
public static final String DORIC_BUNDLE_LIB = "doric-lib.js";
public static final String DORIC_MODULE_LIB = "./index";
public static final String INJECT_LOG = "nativeLog";
public static final String INJECT_REQUIRE = "nativeRequire";
public static final String INJECT_TIMER_SET = "nativeSetTimer";
public static final String INJECT_TIMER_CLEAR = "nativeClearTimer";
public static final String INJECT_BRIDGE = "nativeBridge";
public static final String TEMPLATE_CONTEXT_CREATE = "Reflect.apply(" +
"function(doric,context,require,exports){" + "\n" +
"%s" + "\n" +
"},doric.jsObtainContext(\"%s\"),[" +
"undefined," +
"doric.jsObtainContext(\"%s\")," +
"doric.__require__" +
",{}" +
"])";
public static final String TEMPLATE_MODULE = "Reflect.apply(doric.jsRegisterModule,this,[" +
"\"%s\"," +
"Reflect.apply(function(__module){" +
"(function(module,exports,require){" + "\n" +
"%s" + "\n" +
"})(__module,__module.exports,doric.__require__);" +
"\nreturn __module.exports;" +
"},this,[{exports:{}}])" +
"])";
public static final String TEMPLATE_CONTEXT_DESTROY = "doric.jsRelease(%s)";
public static final String GLOBAL_DORIC = "doric";
public static final String DORIC_CONTEXT_RELEASE = "jsReleaseContext";
public static final String DORIC_CONTEXT_INVOKE = "jsCallEntityMethod";
public static final String DORIC_TIMER_CALLBACK = "jsCallbackTimer";
}

View File

@@ -0,0 +1,38 @@
package com.github.pengfeizhou.doric.utils;
import android.util.Log;
import com.github.pengfeizhou.doric.Doric;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class DoricLog {
private static String TAG = Doric.class.getSimpleName();
public static void d(String message, String... suffix) {
StringBuilder stringBuilder = new StringBuilder(TAG);
for (String s : suffix) {
stringBuilder.append(s);
}
Log.d(stringBuilder.toString(), message);
}
public static void w(String message, String... suffix) {
StringBuilder stringBuilder = new StringBuilder(TAG);
for (String s : suffix) {
stringBuilder.append(s);
}
Log.w(stringBuilder.toString(), message);
}
public static void e(String message, String... suffix) {
StringBuilder stringBuilder = new StringBuilder(TAG);
for (String s : suffix) {
stringBuilder.append(s);
}
Log.e(stringBuilder.toString(), message);
}
}

View File

@@ -0,0 +1,58 @@
package com.github.pengfeizhou.doric.utils;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
import java.util.concurrent.CountDownLatch;
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> {
private final CountDownLatch mReadyLatch = new CountDownLatch(1);
private volatile
T mResult;
/**
* Sets the result. If another thread has called {@link #get}, they will immediately receive the
* value. Must only be called once.
*/
public void set(T result) {
if (mReadyLatch.getCount() == 0) {
throw new RuntimeException("Result has already been set!");
}
mResult = result;
mReadyLatch.countDown();
}
/**
* Wait up to the timeout time for another Thread to set a value on this future. If a value has
* already been set, this method will return immediately.
* <p>
* NB: For simplicity, we catch and wrap InterruptedException. Do NOT use this class if you
* are in the 1% of cases where you actually want to handle that.
*/
public T get(long timeoutMS) {
try {
if (!mReadyLatch.await(timeoutMS, TimeUnit.MILLISECONDS)) {
throw new TimeoutException();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return mResult;
}
public static class TimeoutException extends RuntimeException {
public TimeoutException() {
super("Timed out waiting for future");
}
}
}

View File

@@ -0,0 +1,38 @@
package com.github.pengfeizhou.doric.utils;
import android.content.res.AssetManager;
import com.github.pengfeizhou.doric.Doric;
import java.io.IOException;
import java.io.InputStream;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class DoricUtils {
public static String readAssetFile(String assetFile) {
InputStream inputStream = null;
try {
AssetManager assetManager = Doric.application().getAssets();
inputStream = assetManager.open(assetFile);
int length = inputStream.available();
byte[] buffer = new byte[length];
inputStream.read(buffer);
return new String(buffer);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return "";
}
}

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">Doric</string>
</resources>