diff --git a/android/hummer-core/src/main/java/com/didi/hummer/core/engine/napi/NAPICallback.java b/android/hummer-core/src/main/java/com/didi/hummer/core/engine/napi/NAPICallback.java index c42c4efe2..1baa74eba 100644 --- a/android/hummer-core/src/main/java/com/didi/hummer/core/engine/napi/NAPICallback.java +++ b/android/hummer-core/src/main/java/com/didi/hummer/core/engine/napi/NAPICallback.java @@ -17,7 +17,6 @@ public static NAPICallback wrapper(long context, long value) { private NAPICallback(long context, long value) { super(context, value); - protect(); } @MainThread diff --git a/android/hummer-core/src/main/java/com/didi/hummer/core/engine/napi/NAPIValue.java b/android/hummer-core/src/main/java/com/didi/hummer/core/engine/napi/NAPIValue.java index 9bc2f6076..2339a514b 100644 --- a/android/hummer-core/src/main/java/com/didi/hummer/core/engine/napi/NAPIValue.java +++ b/android/hummer-core/src/main/java/com/didi/hummer/core/engine/napi/NAPIValue.java @@ -18,7 +18,6 @@ public class NAPIValue implements JSValue { public long context; public long value; - private volatile boolean isUnprotected = true; public static NAPIValue wrapper(long context, long value) { return new NAPIValue(context, value); @@ -242,20 +241,14 @@ public boolean isNull() { @Override public void protect() { UIThreadUtil.assetOnMainThreadCall("NAPIValue.protect"); - if (isUnprotected) { - isUnprotected = false; - JSEngine.protect(context, value); - } + JSEngine.protect(context, value); } @MainThread @Override public void unprotect() { UIThreadUtil.assetOnMainThreadCall("NAPIValue.unprotect"); - if (!isUnprotected) { - isUnprotected = true; - JSEngine.unprotect(context, value); - } + JSEngine.unprotect(context, value); } @Override @@ -287,7 +280,6 @@ public String toString() { return "NAPIValue{" + "context=" + context + ", value=" + value + - ", isUnprotected=" + isUnprotected + '}'; } } diff --git a/android/hummer-core/src/main/jni/napi/hummer/JSEngine.cpp b/android/hummer-core/src/main/jni/napi/hummer/JSEngine.cpp index 24e3e64bc..faf4a9f52 100644 --- a/android/hummer-core/src/main/jni/napi/hummer/JSEngine.cpp +++ b/android/hummer-core/src/main/jni/napi/hummer/JSEngine.cpp @@ -34,12 +34,12 @@ static NAPIValue invoke(NAPIEnv globalEnv, NAPICallbackInfo info) { env->DeleteLocalRef(params); JNI_DetachEnv(); - NAPIHandleScope handleScope; - napi_open_handle_scope(globalEnv, &handleScope); +// NAPIHandleScope handleScope; +// napi_open_handle_scope(globalEnv, &handleScope); NAPIValue r = JSUtils::JavaObjectToJsValue(globalEnv, ret); - napi_close_handle_scope(globalEnv, handleScope); +// napi_close_handle_scope(globalEnv, handleScope); return r; } @@ -113,7 +113,7 @@ Java_com_didi_hummer_core_engine_napi_jni_JSEngine_evaluateJavaScript(JNIEnv *en return obj; } - return JSUtils::JsValueToJavaObject(globalEnv, result); + return JSUtils::JsValueToJavaObject(globalEnv, result, true); } extern "C" @@ -168,7 +168,7 @@ Java_com_didi_hummer_core_engine_napi_jni_JSEngine_evaluateBytecode(JNIEnv *env, return obj; } - return JSUtils::JsValueToJavaObject(globalEnv, result); + return JSUtils::JsValueToJavaObject(globalEnv, result, true); } extern "C" @@ -219,7 +219,7 @@ Java_com_didi_hummer_core_engine_napi_jni_JSEngine_getProperty(JNIEnv *env, jcla } env->ReleaseStringUTFChars(key, cKey); - jobject r = JSUtils::JsValueToJavaObject(globalEnv, ret); + jobject r = JSUtils::JsValueToJavaObject(globalEnv, ret, true); napi_close_handle_scope(globalEnv, handleScope); return r; @@ -314,7 +314,7 @@ Java_com_didi_hummer_core_engine_napi_jni_JSEngine_callFunction(JNIEnv *env, jcl return nullptr; } - jobject r = JSUtils::JsValueToJavaObject(globalEnv, result); + jobject r = JSUtils::JsValueToJavaObject(globalEnv, result, true); napi_close_handle_scope(globalEnv, handleScope); return r; } @@ -333,20 +333,8 @@ Java_com_didi_hummer_core_engine_napi_jni_JSEngine_isJSValueValid(JNIEnv *env, j if (globalEnv == nullptr) { return false; } - - NAPIHandleScope handleScope; - napi_open_handle_scope(globalEnv, &handleScope); - - auto value = JSUtils::toJsValue(globalEnv, js_value); - NAPIValueType type; - auto status = napi_typeof(globalEnv, value, &type); - - napi_close_handle_scope(globalEnv, handleScope); - - if (status != NAPICommonOK) { - return false; - } - return type != NAPIUndefined && type != NAPINull; + auto valueRef = JSUtils::toJsValueRef(js_value); + return JSUtils::isJSValueValid(globalEnv, valueRef); } extern "C" @@ -356,28 +344,18 @@ Java_com_didi_hummer_core_engine_napi_jni_JSEngine_isJSValueEqual(JNIEnv *env, j if (globalEnv == nullptr) { return false; } - - NAPIHandleScope handleScope; - napi_open_handle_scope(globalEnv, &handleScope); - - auto valueLeft = JSUtils::toJsValue(globalEnv, js_value_l); - auto valueRight = JSUtils::toJsValue(globalEnv, js_value_r); - - bool ret; - auto status = napi_strict_equals(globalEnv, valueLeft, valueRight, &ret); - - napi_close_handle_scope(globalEnv, handleScope); - - if (status != NAPIExceptionOK) { - return false; - } - return ret; + auto valueRefLeft = JSUtils::toJsValueRef(js_value_l); + auto valueRefRight = JSUtils::toJsValueRef(js_value_r); + return JSUtils::isJSValueEqual(globalEnv, valueRefLeft, valueRefRight); } extern "C" JNIEXPORT void JNICALL Java_com_didi_hummer_core_engine_napi_jni_JSEngine_protect(JNIEnv *env, jclass clazz, jlong js_context, jlong js_value) { auto globalEnv = JSUtils::toJsContext(js_context); + if (globalEnv == nullptr) { + return; + } auto valueRef = JSUtils::toJsValueRef(js_value); napi_reference_ref(globalEnv, valueRef, nullptr); } diff --git a/android/hummer-core/src/main/jni/napi/hummer/JSUtils.cpp b/android/hummer-core/src/main/jni/napi/hummer/JSUtils.cpp index bd45054e2..e052b4f49 100644 --- a/android/hummer-core/src/main/jni/napi/hummer/JSUtils.cpp +++ b/android/hummer-core/src/main/jni/napi/hummer/JSUtils.cpp @@ -121,7 +121,11 @@ int64_t JSUtils::toJsValuePtr(NAPIRef valueRef) { } int64_t JSUtils::toJsValuePtr(NAPIEnv env, NAPIValue value) { - return toJsValuePtr(createJsValueRef(env, value)); + return JSUtils::toJsValuePtr(env, value, false); +} + +int64_t JSUtils::toJsValuePtr(NAPIEnv env, NAPIValue value, bool isStrongRef) { + return toJsValuePtr(createJsValueRef(env, value, isStrongRef)); } NAPIValue JSUtils::toJsValue(NAPIEnv env, int64_t valuePtr) { @@ -146,13 +150,13 @@ NAPIValue JSUtils::getJsValueFromRef(NAPIEnv env, NAPIRef valueRef) { return value; } -NAPIRef JSUtils::createJsValueRef(NAPIEnv env, NAPIValue value) { +NAPIRef JSUtils::createJsValueRef(NAPIEnv env, NAPIValue value, bool isStrongRef) { if (value == nullptr) { return nullptr; } NAPIRef valueRef; - auto status = napi_create_reference(env, value, 0, &valueRef); + auto status = napi_create_reference(env, value, isStrongRef ? 1 : 0, &valueRef); if (status != NAPIExceptionOK) { return nullptr; } @@ -213,6 +217,10 @@ NAPIValue JSUtils::createJsUndefined(NAPIEnv env) { } jobject JSUtils::JsValueToJavaObject(NAPIEnv globalEnv, NAPIValue value) { + return JSUtils::JsValueToJavaObject(globalEnv, value, false); +} + +jobject JSUtils::JsValueToJavaObject(NAPIEnv globalEnv, NAPIValue value, bool isStrongRef) { JNIEnv* env = JNI_GetEnv(); NAPIValueType type; auto status = napi_typeof(globalEnv, value, &type); @@ -234,11 +242,11 @@ jobject JSUtils::JsValueToJavaObject(NAPIEnv globalEnv, NAPIValue value) { obj = JSUtils::toJavaString(globalEnv, value); } else if (type == NAPIFunction) { jlong ctxPtr = JSUtils::toJsContextPtr(globalEnv); - jlong valuePtr = JSUtils::toJsValuePtr(globalEnv, value); + jlong valuePtr = JSUtils::toJsValuePtr(globalEnv, value, true); obj = env->CallStaticObjectMethod(jsCallbackCls, jsCallbackInitMethodID, ctxPtr, valuePtr); } else { jlong ctxPtr = JSUtils::toJsContextPtr(globalEnv); - jlong valuePtr = JSUtils::toJsValuePtr(globalEnv, value); + jlong valuePtr = JSUtils::toJsValuePtr(globalEnv, value, isStrongRef); obj = env->CallStaticObjectMethod(jsValueCls, jsValueInitMethodID, ctxPtr, valuePtr); } @@ -276,6 +284,47 @@ NAPIValue JSUtils::JavaObjectToJsValue(NAPIEnv globalEnv, jobject value) { return val; } +bool JSUtils::isJSValueValid(NAPIEnv env, NAPIValue value) { + NAPIValueType type; + auto status = napi_typeof(env, value, &type); + if (status != NAPICommonOK) { + return false; + } + return type != NAPIUndefined && type != NAPINull; +} + +bool JSUtils::isJSValueValid(NAPIEnv env, NAPIRef valueRef) { + NAPIHandleScope handleScope; + napi_open_handle_scope(env, &handleScope); + + auto ret = isJSValueValid(env, getJsValueFromRef(env, valueRef)); + + napi_close_handle_scope(env, handleScope); + return ret; +} + +bool JSUtils::isJSValueEqual(NAPIEnv env, NAPIValue valueLeft, NAPIValue valueRight) { + bool ret; + auto status = napi_strict_equals(env, valueLeft, valueRight, &ret); + + if (status != NAPIExceptionOK) { + return false; + } + return ret; +} + +bool JSUtils::isJSValueEqual(NAPIEnv env, NAPIRef valueRefLeft, NAPIRef valueRefRight) { + NAPIHandleScope handleScope; + napi_open_handle_scope(env, &handleScope); + + auto valueLeft = getJsValueFromRef(env, valueRefLeft); + auto valueRight = getJsValueFromRef(env, valueRefRight); + bool ret = isJSValueEqual(env, valueLeft, valueRight); + + napi_close_handle_scope(env, handleScope); + return ret; +} + void JSUtils::printDumpReferenceTables(JNIEnv *env) { jclass vm_class = (*env).FindClass("dalvik/system/VMDebug"); jmethodID dump_mid = env->GetStaticMethodID(vm_class, "dumpReferenceTables", "()V"); diff --git a/android/hummer-core/src/main/jni/napi/hummer/JSUtils.h b/android/hummer-core/src/main/jni/napi/hummer/JSUtils.h index ef1fcbb1f..7d9b7c45d 100644 --- a/android/hummer-core/src/main/jni/napi/hummer/JSUtils.h +++ b/android/hummer-core/src/main/jni/napi/hummer/JSUtils.h @@ -49,9 +49,10 @@ class JSUtils { static NAPIRef toJsValueRef(int64_t valuePtr); static int64_t toJsValuePtr(NAPIRef valueRef); static int64_t toJsValuePtr(NAPIEnv env, NAPIValue value); + static int64_t toJsValuePtr(NAPIEnv env, NAPIValue value, bool isStrongRef); static NAPIValue toJsValue(NAPIEnv env, int64_t valuePtr); static NAPIValue getJsValueFromRef(NAPIEnv env, NAPIRef valueRef); - static NAPIRef createJsValueRef(NAPIEnv env, NAPIValue value); + static NAPIRef createJsValueRef(NAPIEnv env, NAPIValue value, bool isStrongRef); static const char *toCString(NAPIEnv env, NAPIValue value); static void freeCString(NAPIEnv env, const char *cString); @@ -62,8 +63,14 @@ class JSUtils { static NAPIValue createJsUndefined(NAPIEnv env); static jobject JsValueToJavaObject(NAPIEnv env, NAPIValue value); + static jobject JsValueToJavaObject(NAPIEnv env, NAPIValue value, bool isStrongRef); static NAPIValue JavaObjectToJsValue(NAPIEnv globalEnv, jobject value); + static bool isJSValueValid(NAPIEnv env, NAPIValue value); + static bool isJSValueValid(NAPIEnv env, NAPIRef valueRef); + static bool isJSValueEqual(NAPIEnv env, NAPIValue valueLeft, NAPIValue valueRight); + static bool isJSValueEqual(NAPIEnv env, NAPIRef valueRefLeft, NAPIRef valueRight); + static void printDumpReferenceTables(JNIEnv *env); private: diff --git a/android/hummer-sdk/src/main/java/com/didi/hummer/module/Request.java b/android/hummer-sdk/src/main/java/com/didi/hummer/module/Request.java index c1bda83aa..c0847ff82 100644 --- a/android/hummer-sdk/src/main/java/com/didi/hummer/module/Request.java +++ b/android/hummer-sdk/src/main/java/com/didi/hummer/module/Request.java @@ -58,7 +58,6 @@ public void onCreate() {} @Override public void onDestroy() { isDestroyed.set(true); - jsValue.unprotect(); } public void setUrl(String api) { diff --git a/android/hummer-sdk/src/main/java/com/didi/hummer/module/Timer.java b/android/hummer-sdk/src/main/java/com/didi/hummer/module/Timer.java index ffc81cdee..e5c9f786c 100644 --- a/android/hummer-sdk/src/main/java/com/didi/hummer/module/Timer.java +++ b/android/hummer-sdk/src/main/java/com/didi/hummer/module/Timer.java @@ -19,7 +19,7 @@ @Component("Timer") public class Timer implements ILifeCycle { - private static Handler timerHandler = new Handler(Looper.getMainLooper()); + private Handler timerHandler = new Handler(Looper.getMainLooper()); private JSValue jsValue; private Runnable intervalRunnable; @@ -43,8 +43,12 @@ public void onCreate() { @Override public void onDestroy() { isDestroyed.set(true); - clearInterval(); - clearTimeout(); + if (intervalRunnable != null) { + timerHandler.removeCallbacks(intervalRunnable); + } + if (timeoutRunnable != null) { + timerHandler.removeCallbacks(timeoutRunnable); + } } /** diff --git a/examples/hummer/unit-test/.vscode/launch.json b/examples/hummer/unit-test/.vscode/launch.json index 409d61c2d..cf70aa3b2 100644 --- a/examples/hummer/unit-test/.vscode/launch.json +++ b/examples/hummer/unit-test/.vscode/launch.json @@ -7,5 +7,6 @@ "type": "hummerdirect", "workspaceRoot": "${workspaceFolder}", "request": "attach", + "port": 8000 }] } \ No newline at end of file diff --git a/examples/hummer/unit-test/src/Comp_Input.js b/examples/hummer/unit-test/src/Comp_Input.js index dccfdb2b2..be27ab5aa 100644 --- a/examples/hummer/unit-test/src/Comp_Input.js +++ b/examples/hummer/unit-test/src/Comp_Input.js @@ -105,7 +105,7 @@ class RootView extends View { let infoText = new Text(); - subLayout1.appendChild(input); + subLayout1.appendChild(this.feeInput); subLayout1.appendChild(btn1); subLayout2.appendChild(textArea); subLayout2.appendChild(btn2); diff --git a/examples/hummer/unit-test/src/Comp_List.js b/examples/hummer/unit-test/src/Comp_List.js index c71e74c7c..bac01d3b9 100644 --- a/examples/hummer/unit-test/src/Comp_List.js +++ b/examples/hummer/unit-test/src/Comp_List.js @@ -3,6 +3,7 @@ const TYPE_ITEM = 2; const ITEM_COUNT = 20; +let stextView = new Text(); class RootView extends View { constructor() { super(); @@ -14,7 +15,7 @@ class RootView extends View { this.listView = new List(); this.listView.style = { width: '100%', - height: '100%', + height: '50%', mode: "list", // mode: "grid", // mode: "waterfall", @@ -99,6 +100,16 @@ class RootView extends View { this.appendChild(this.listView); + + stextView.text = "~ Hello Hummer ~"; + stextView.style = { + width: 100, + height: 100, + fontSize: 20, + color: '#000000', + } + this.appendChild(stextView); + this.loadData(); } @@ -147,7 +158,7 @@ class ItemCell extends View { this.textView = new Text(); this.textView.style = { - height: 30, + height: 80, textAlign: "center", }; @@ -160,10 +171,39 @@ class ItemCell extends View { this.appendChild(this.textView); // this.appendChild(lineView); + + + // let isIntercepted = false; + // this.addEventListener('pan', event => { + // if (event.state == 1) { + // console.log("event: start"); + // isIntercepted = false; + // } else if (event.state == 2) { + // console.log("event: ", event); + // console.log("ๅ็งป้‡: ", event.translation.deltaX); + + // if (Math.abs(event.translation.deltaX) > 3 && !isIntercepted) { + // isIntercepted = true; + // requestDisallowInterceptTouchEvent(this, true); + // } + // } else if (event.state == 3) { + // console.log("event: end"); + // isIntercepted = false; + // } + // }) + + stextView.text = 's'; + // stextView.style = { + // width: 111, + // } } refresh(position) { this.textView.text = position.toString(); + + // this.feeInput.text = '' + + // stextView.text = 's'; } } diff --git a/examples/hummer/unit-test/src/HelloWorld.js b/examples/hummer/unit-test/src/HelloWorld.js index 71347f0cf..be839a6e0 100644 --- a/examples/hummer/unit-test/src/HelloWorld.js +++ b/examples/hummer/unit-test/src/HelloWorld.js @@ -7,17 +7,98 @@ class RootView extends View { height: '100%', justifyContent: 'center', alignItems: 'center', - backgroundColor: '#FFFFFF', + backgroundColor: '#FFFF00', } - let textView = new Text(); - textView.text = "~ Hello Hummer ~"; + let textView = new Text(11); + textView.text = "~ Hello Hummer~"; textView.style = { fontSize: 20, - color: '#000000', + color: '#FF0000', } + let v = new View(); + let t = new Text(); + t.text = '111'; + v.appendChild(t); + this.appendChild(textView); + this.appendChild(v); + + + let vv = new View(); + this.l = (event) => { + let vvv = vv; + this.removeChild(v); + textView.removeEventListener('tap', this.l); + // textView.removeEventListener('tap'); + this.l = undefined; + + // this.f(textView); + + // this.removeChild(v); + // this.removeChild(textView); + // v=undefined; + } + textView.addEventListener('tap', ()=>{}); + textView.addEventListener('tap', this.l); + textView.addEventListener('tap', ()=>{}); + + // this.removeChild(v); + // textView.removeEventListener('tap', this.l); + // this.l = undefined; + + + // let rr = new View(); + // setTimeout(() => { + // // let rrr = rr; + // console.log('timeout'); + // // this.removeChild(v); + // textView.removeEventListener('tap', this.l); + // this.l = undefined; + // }, 3000); + + + + // Promise.resolve().then(() => { + // console.log('do sth'); + // textView.removeEventListener('tap', this.l); + // this.l = undefined; + // }) + + console.log('end...'); + + let ttt = this.getElementById(11); + console.log('end...'); + console.log('end...'); + console.log('end...'); + console.log('end...'); + console.log('end...'); + console.log('end...'); + console.log('end...'); + console.log('end...'); + console.log('end...'); + console.log('end...'); + console.log('end...'); + + + Promise.resolve().then(() => { + ttt.text = '222'; + }) + } + + f(textView) { + // this.removeChild(v); + + // setTimeout(() => { + // console.log('timeout'); + // textView.removeEventListener('tap', this.l); + // this.l = undefined; + // // this.removeChild(v); + // }, 1000); + + textView.removeEventListener('tap', this.l); + this.l = undefined; } } diff --git a/examples/hummer/unit-test/src/Test_Callback.js b/examples/hummer/unit-test/src/Test_Callback.js index 2c359b38d..3e8b21e1b 100644 --- a/examples/hummer/unit-test/src/Test_Callback.js +++ b/examples/hummer/unit-test/src/Test_Callback.js @@ -74,13 +74,13 @@ class RootView extends View { }); let info = "Test.nativeFunc: " + ret + "\n"; - new Timer().setTimeout(() => { - // JS -> Native - ret = this.nativeFunc(111, 222.22); - info += "this.nativeFunc: " + ret; + // new Timer().setTimeout(() => { + // // JS -> Native + // ret = this.nativeFunc(111, 222.22); + // info += "this.nativeFunc: " + ret; - infoText.text = info; - }, 1000); + // infoText.text = info; + // }, 1000); infoText.text = info; @@ -89,31 +89,31 @@ class RootView extends View { this.appendChild(layout); } - // Native -> JS - onTestBase(p1, p2, p3, p4) { - infoText.text += "this.onTestBase: p1 = " + p1 + ", p2 = " + p2 + ", p3 = " + p3 + ", p4 = " + p4 + "\n"; - return "111" - } - - // Native -> JS - onTestCollection(p1, p2) { - infoText.text += "this.onTestCollection: p1 = " + JSON.stringify(p1) + ", p2 = " + JSON.stringify(p2); - return "222" - } + // // Native -> JS + // onTestBase(p1, p2, p3, p4) { + // infoText.text += "this.onTestBase: p1 = " + p1 + ", p2 = " + p2 + ", p3 = " + p3 + ", p4 = " + p4 + "\n"; + // return "111" + // } + + // // Native -> JS + // onTestCollection(p1, p2) { + // infoText.text += "this.onTestCollection: p1 = " + JSON.stringify(p1) + ", p2 = " + JSON.stringify(p2); + // return "222" + // } } var infoText; -// Native -> JS -globalThis.onTestBase = (p1, p2, p3, p4) => { - infoText.text += "Global.onTestBase: p1 = " + p1 + ", p2 = " + p2 + ", p3 = " + p3 + ", p4 = " + p4 + "\n"; - return "333" -} - -// Native -> JS -globalThis.onTestCollection = (p1, p2) => { - infoText.text += "Global.onTestCollection: p1 = " + JSON.stringify(p1) + ", p2 = " + JSON.stringify(p2) + "\n"; - return "444" -} +// // Native -> JS +// globalThis.onTestBase = (p1, p2, p3, p4) => { +// infoText.text += "Global.onTestBase: p1 = " + p1 + ", p2 = " + p2 + ", p3 = " + p3 + ", p4 = " + p4 + "\n"; +// return "333" +// } + +// // Native -> JS +// globalThis.onTestCollection = (p1, p2) => { +// infoText.text += "Global.onTestCollection: p1 = " + JSON.stringify(p1) + ", p2 = " + JSON.stringify(p2) + "\n"; +// return "444" +// } Hummer.render(new RootView()); \ No newline at end of file