diff --git a/Android/app/src/main/java/pub/doric/demo/MainActivity.java b/Android/app/src/main/java/pub/doric/demo/MainActivity.java index 60d5c84c..96ea5dc1 100644 --- a/Android/app/src/main/java/pub/doric/demo/MainActivity.java +++ b/Android/app/src/main/java/pub/doric/demo/MainActivity.java @@ -49,7 +49,6 @@ public class MainActivity extends AppCompatActivity { setContentView(R.layout.activity_main); doricContext = DoricContext.create(this, DoricUtils.readAssetFile("demo/Snake.js"), "test"); doricContext.init(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); -// doricContext.callEntity("log"); doricContext.getRootNode().setRootView((FrameLayout) findViewById(R.id.root)); LocalServer localServer = new LocalServer(getApplicationContext(), 8910); diff --git a/Android/doric/src/main/java/pub/doric/DoricRegistry.java b/Android/doric/src/main/java/pub/doric/DoricRegistry.java index 8bb597b3..edc337b6 100644 --- a/Android/doric/src/main/java/pub/doric/DoricRegistry.java +++ b/Android/doric/src/main/java/pub/doric/DoricRegistry.java @@ -20,6 +20,7 @@ import android.text.TextUtils; import pub.doric.plugin.ShaderPlugin; import pub.doric.shader.HLayoutNode; import pub.doric.shader.ImageNode; +import pub.doric.shader.list.ListItemNode; import pub.doric.shader.list.ListNode; import pub.doric.shader.RootNode; import pub.doric.shader.StackNode; @@ -68,6 +69,7 @@ public class DoricRegistry { this.registerViewNode(VLayoutNode.class); this.registerViewNode(HLayoutNode.class); this.registerViewNode(ListNode.class); + this.registerViewNode(ListItemNode.class); initRegistry(this); } diff --git a/Android/doric/src/main/java/pub/doric/async/SettableFuture.java b/Android/doric/src/main/java/pub/doric/async/SettableFuture.java index 31b397bc..1764eb8e 100644 --- a/Android/doric/src/main/java/pub/doric/async/SettableFuture.java +++ b/Android/doric/src/main/java/pub/doric/async/SettableFuture.java @@ -64,6 +64,15 @@ public class SettableFuture { return mResult; } + public T get() { + try { + mReadyLatch.await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return mResult; + } + public static class TimeoutException extends RuntimeException { public TimeoutException() { diff --git a/Android/doric/src/main/java/pub/doric/engine/DoricJSEngine.java b/Android/doric/src/main/java/pub/doric/engine/DoricJSEngine.java index 1509932c..681615fe 100644 --- a/Android/doric/src/main/java/pub/doric/engine/DoricJSEngine.java +++ b/Android/doric/src/main/java/pub/doric/engine/DoricJSEngine.java @@ -197,7 +197,7 @@ public class DoricJSEngine implements Handler.Callback, DoricTimerExtension.Time values.add(DoricUtils.toJavaValue(arg)); } return mDoricJSE.invokeMethod(DoricConstant.GLOBAL_DORIC, method, - values.toArray(new JavaValue[values.size()]), true); + values.toArray(new JavaValue[values.size()]), false); } @Override diff --git a/Android/doric/src/main/java/pub/doric/engine/remote/RemoteJSExecutor.java b/Android/doric/src/main/java/pub/doric/engine/remote/RemoteJSExecutor.java index f4fcac27..0a94997c 100644 --- a/Android/doric/src/main/java/pub/doric/engine/remote/RemoteJSExecutor.java +++ b/Android/doric/src/main/java/pub/doric/engine/remote/RemoteJSExecutor.java @@ -41,7 +41,7 @@ public class RemoteJSExecutor { .readTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .build(); - final Request request = new Request.Builder().url("ws://192.168.25.175:2080").build(); + final Request request = new Request.Builder().url("ws://192.168.24.79:2080").build(); final Thread current = Thread.currentThread(); webSocket = okHttpClient.newWebSocket(request, new WebSocketListener() { diff --git a/Android/doric/src/main/java/pub/doric/shader/GroupNode.java b/Android/doric/src/main/java/pub/doric/shader/GroupNode.java index dd1e690e..1f787c7f 100644 --- a/Android/doric/src/main/java/pub/doric/shader/GroupNode.java +++ b/Android/doric/src/main/java/pub/doric/shader/GroupNode.java @@ -68,7 +68,7 @@ public abstract class GroupNode extends ViewNode { if (i != child.index) { mIndexInfo.remove(i); child.index = i; - mView.removeView(child.getView()); + mView.removeView(child.getDoricLayer()); } tobeRemoved.remove(child); } @@ -87,7 +87,7 @@ public abstract class GroupNode extends ViewNode { } child.blend(childObj.getProperty("props").asObject(), params); if (mIndexInfo.get(i) == null) { - mView.addView(child.getView(), i, child.getLayoutParams()); + mView.addView(child.getDoricLayer(), i, child.getLayoutParams()); mIndexInfo.put(i, child); } } @@ -98,7 +98,7 @@ public abstract class GroupNode extends ViewNode { mChildrenNode.remove(node.getId()); mIndexInfo.remove(i); tobeRemoved.remove(node); - mView.removeView(node.getView()); + mView.removeView(node.getDoricLayer()); } i++; } diff --git a/Android/doric/src/main/java/pub/doric/shader/RootNode.java b/Android/doric/src/main/java/pub/doric/shader/RootNode.java index fc02a024..8a1f0ff2 100644 --- a/Android/doric/src/main/java/pub/doric/shader/RootNode.java +++ b/Android/doric/src/main/java/pub/doric/shader/RootNode.java @@ -36,7 +36,7 @@ public class RootNode extends StackNode { } @Override - public View getView() { + public View getDoricLayer() { return mView; } diff --git a/Android/doric/src/main/java/pub/doric/shader/ViewNode.java b/Android/doric/src/main/java/pub/doric/shader/ViewNode.java index 6f3bda4d..4f5b83ea 100644 --- a/Android/doric/src/main/java/pub/doric/shader/ViewNode.java +++ b/Android/doric/src/main/java/pub/doric/shader/ViewNode.java @@ -22,11 +22,13 @@ import android.widget.FrameLayout; import pub.doric.DoricContext; import pub.doric.DoricRegistry; +import pub.doric.async.AsyncResult; import pub.doric.utils.DoricContextHolder; import pub.doric.utils.DoricConstant; import pub.doric.utils.DoricMetaInfo; import pub.doric.utils.DoricUtils; +import com.github.pengfeizhou.jscore.JSDecoder; import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSValue; @@ -40,7 +42,7 @@ import java.util.LinkedList; public abstract class ViewNode extends DoricContextHolder { protected T mView; int index; - GroupNode mParent; + ViewNode mParent; String mId; private ViewGroup.LayoutParams mLayoutParams; @@ -50,7 +52,11 @@ public abstract class ViewNode extends DoricContextHolder { private DoricLayer doricLayer; - public View getView() { + public void setParentNode(ViewNode parentNode) { + mParent = parentNode; + } + + public View getDoricLayer() { return doricLayer; } @@ -60,18 +66,20 @@ public abstract class ViewNode extends DoricContextHolder { protected abstract T build(JSObject jsObject); - void blend(JSObject jsObject, ViewGroup.LayoutParams layoutParams) { + public void blend(JSObject jsObject, ViewGroup.LayoutParams layoutParams) { mLayoutParams = layoutParams; if (mView == null) { mView = build(jsObject); } - if (getView() == null) { + if (getDoricLayer() == null) { doricLayer = new DoricLayer(getContext()); FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(layoutParams.width, layoutParams.height); doricLayer.addView(mView, params); } - for (String prop : jsObject.propertySet()) { - blend(mView, layoutParams, prop, jsObject.getProperty(prop)); + if (jsObject != null) { + for (String prop : jsObject.propertySet()) { + blend(mView, layoutParams, prop, jsObject.getProperty(prop)); + } } ViewGroup.LayoutParams params = mView.getLayoutParams(); if (params != null) { @@ -120,8 +128,8 @@ public abstract class ViewNode extends DoricContextHolder { }); break; case "layoutConfig": - if (prop.isObject() && mParent != null) { - mParent.blendChild(this, prop.asObject()); + if (prop.isObject() && mParent instanceof GroupNode) { + ((GroupNode) mParent).blendChild(this, prop.asObject()); } break; case "border": @@ -178,14 +186,14 @@ public abstract class ViewNode extends DoricContextHolder { return ids.toArray(new String[0]); } - public void callJSResponse(String funcId, Object... args) { + public AsyncResult callJSResponse(String funcId, Object... args) { final Object[] nArgs = new Object[args.length + 2]; nArgs[0] = getIdList(); nArgs[1] = funcId; if (args.length > 0) { System.arraycopy(args, 0, nArgs, 2, args.length); } - getDoricContext().callEntity(DoricConstant.DORIC_ENTITY_RESPONSE, nArgs); + return getDoricContext().callEntity(DoricConstant.DORIC_ENTITY_RESPONSE, nArgs); } public static ViewNode create(DoricContext doricContext, String type) { diff --git a/Android/doric/src/main/java/pub/doric/shader/list/ListAdapter.java b/Android/doric/src/main/java/pub/doric/shader/list/ListAdapter.java index d8ad0e6f..56059445 100644 --- a/Android/doric/src/main/java/pub/doric/shader/list/ListAdapter.java +++ b/Android/doric/src/main/java/pub/doric/shader/list/ListAdapter.java @@ -22,7 +22,12 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; +import com.github.pengfeizhou.jscore.JSDecoder; import com.github.pengfeizhou.jscore.JSObject; +import com.github.pengfeizhou.jscore.JSValue; + +import pub.doric.async.AsyncResult; +import pub.doric.shader.ViewNode; /** * @Description: com.github.penfeizhou.doric.widget @@ -33,7 +38,7 @@ public class ListAdapter extends RecyclerView.Adapter itemObjects = new SparseArray<>(); @@ -45,12 +50,15 @@ public class ListAdapter extends RecyclerView.Adapter asyncResult = listNode.callJSResponse( + renderBunchedItemsFuncId, + position, + batchCount); + try { + JSDecoder jsDecoder = asyncResult.synchronous().get(); + JSValue result = jsDecoder.decode(); + if (result.isArray()) { + JSValue[] values = result.asArray().toArray(); + for (int i = 0; i < values.length; i++) { + itemObjects.put(i + position, values[i].asObject()); + } + return values[0].asObject(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + return itemModel; } - public static class DoricViewHolder extends RecyclerView.ViewHolder { - public DoricViewHolder(@NonNull View itemView) { + static class DoricViewHolder extends RecyclerView.ViewHolder { + ListItemNode listItemNode; + + public DoricViewHolder(ListItemNode node, @NonNull View itemView) { super(itemView); + listItemNode = node; } } } diff --git a/Android/doric/src/main/java/pub/doric/shader/list/ListItemNode.java b/Android/doric/src/main/java/pub/doric/shader/list/ListItemNode.java new file mode 100644 index 00000000..c06b1316 --- /dev/null +++ b/Android/doric/src/main/java/pub/doric/shader/list/ListItemNode.java @@ -0,0 +1,53 @@ +/* + * Copyright [2019] [Doric.Pub] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package pub.doric.shader.list; + +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import com.github.pengfeizhou.jscore.JSValue; + +import pub.doric.DoricContext; +import pub.doric.extension.bridge.DoricPlugin; +import pub.doric.shader.StackNode; + +/** + * @Description: com.github.penfeizhou.doric.widget + * @Author: pengfei.zhou + * @CreateDate: 2019-11-12 + */ +@DoricPlugin(name = "ListItem") +public class ListItemNode extends StackNode { + public String identifier = ""; + + public ListItemNode(DoricContext doricContext) { + super(doricContext); + this.mView = this.build(null); + ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + this.blend(null, params); + getDoricLayer().setLayoutParams(params); + } + + @Override + protected void blend(FrameLayout view, ViewGroup.LayoutParams layoutParams, String name, JSValue prop) { + if ("identifier".equals(name)) { + this.identifier = prop.asString().value(); + } else { + super.blend(view, layoutParams, name, prop); + } + } +} diff --git a/Android/doric/src/main/java/pub/doric/shader/list/ListNode.java b/Android/doric/src/main/java/pub/doric/shader/list/ListNode.java index 43b6b64a..ff237476 100644 --- a/Android/doric/src/main/java/pub/doric/shader/list/ListNode.java +++ b/Android/doric/src/main/java/pub/doric/shader/list/ListNode.java @@ -17,6 +17,7 @@ package pub.doric.shader.list; import android.view.ViewGroup; +import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.github.pengfeizhou.jscore.JSObject; @@ -42,7 +43,23 @@ public class ListNode extends ViewNode { @Override protected RecyclerView build(JSObject jsObject) { - return new RecyclerView(getContext()); + RecyclerView recyclerView = new RecyclerView(getContext()); + recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + recyclerView.setAdapter(this.listAdapter); + return recyclerView; + } + + @Override + public void blend(JSObject jsObject, ViewGroup.LayoutParams layoutParams) { + super.blend(jsObject, layoutParams); + if (mView != null) { + mView.post(new Runnable() { + @Override + public void run() { + listAdapter.notifyDataSetChanged(); + } + }); + } } @Override @@ -54,9 +71,6 @@ public class ListNode extends ViewNode { case "renderItem": this.listAdapter.renderItemFuncId = prop.asString().value(); break; - case "renderBunchedItemsFuncId": - this.listAdapter.renderBunchedItemsFuncId = prop.asString().value(); - break; case "batchCount": this.listAdapter.batchCount = 15; break; diff --git a/Android/gradle.properties b/Android/gradle.properties index d546deaf..e02581ed 100644 --- a/Android/gradle.properties +++ b/Android/gradle.properties @@ -14,4 +14,9 @@ org.gradle.jvmargs=-Xmx1536m # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true +# To re-enable the build cache, either delete the following +# line or set the property to 'true'. +android.enableBuildCache=false + + diff --git a/demo/src/ListDemo.ts b/demo/src/ListDemo.ts index a041e25c..b6b4bdb9 100644 --- a/demo/src/ListDemo.ts +++ b/demo/src/ListDemo.ts @@ -1,4 +1,4 @@ -import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, ListItem } from "doric"; +import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, ListItem, NativeCall } from "doric"; @Entry class ListPanel extends Panel { @@ -22,5 +22,4 @@ class ListPanel extends Panel { return item } } - } \ No newline at end of file diff --git a/js-framework/src/runtime/sandbox.ts b/js-framework/src/runtime/sandbox.ts index 4e2c74d9..9f488166 100644 --- a/js-framework/src/runtime/sandbox.ts +++ b/js-framework/src/runtime/sandbox.ts @@ -230,6 +230,7 @@ export function jsCallEntityMethod(contextId: string, methodName: string, args?: hookBeforeNativeCall(context) const ret = Reflect.apply(Reflect.get(context.entity, methodName), context.entity, argumentsList) hookAfterNativeCall(context) + loge(methodName, ret) return ret } else { loge(`Cannot find method for context id:${contextId},method name is:${methodName}`) diff --git a/js-framework/src/ui/listview.ts b/js-framework/src/ui/listview.ts index ad0b3f0e..dc8d190e 100644 --- a/js-framework/src/ui/listview.ts +++ b/js-framework/src/ui/listview.ts @@ -34,7 +34,6 @@ export class ListItem extends Stack { */ @Property identifier?: string - list!: List } export class List extends Superview { @@ -61,14 +60,16 @@ export class List extends Superview { let view = this.cachedViews.get(`${itemIdx}`) if (view === undefined) { view = this.renderItem(itemIdx) - view.list = this + view.superview = this this.cachedViews.set(`${itemIdx}`, view) } return view } - @Property - private renderBunchedItems(items: number[]): ListItem[] { - return items.map(e => this.getItem(e)) + private renderBunchedItems(start: number, length: number) { + return new Array(Math.min(length, this.itemCount - start)).fill(0).map((_, idx) => { + const listItem = this.getItem(start + idx) + return listItem.toModel() + }) } } \ No newline at end of file diff --git a/js-framework/src/ui/panel.ts b/js-framework/src/ui/panel.ts index 245e1454..3aa81b27 100644 --- a/js-framework/src/ui/panel.ts +++ b/js-framework/src/ui/panel.ts @@ -94,7 +94,7 @@ export abstract class Panel { for (let i = 2; i < arguments.length; i++) { argumentsList.push(arguments[i]) } - Reflect.apply(v.responseCallback, v, argumentsList) + return Reflect.apply(v.responseCallback, v, argumentsList) } private retrospectView(ids: string[]): View { diff --git a/js-framework/src/ui/view.ts b/js-framework/src/ui/view.ts index b955a3f6..53b244f8 100644 --- a/js-framework/src/ui/view.ts +++ b/js-framework/src/ui/view.ts @@ -121,7 +121,10 @@ export abstract class View implements Modeling, IView { } private id2Callback(id: string) { - const f = this.callbacks.get(id) + let f = this.callbacks.get(id) + if (f === undefined) { + f = Reflect.get(this, id) as Function + } return f } @@ -228,7 +231,7 @@ export abstract class View implements Modeling, IView { for (let i = 1; i < arguments.length; i++) { argumentsList.push(arguments[i]) } - Reflect.apply(f, this, argumentsList) + return Reflect.apply(f, this, argumentsList) } else { loge(`Cannot find callback:${id} for ${JSON.stringify(this.toModel())}`) }