From 139a8775d49b6d8867d493c45e8b3d6916f1257f Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 25 Mar 2020 13:48:58 +0800 Subject: [PATCH] android:add JSDispatcher to optimize scrollchange callback --- .../java/pub/doric/shader/ScrollerNode.java | 21 +++-- .../shader/flowlayout/FlowLayoutNode.java | 21 +++-- .../java/pub/doric/shader/list/ListNode.java | 21 +++-- .../pub/doric/utils/DoricJSDispatcher.java | 85 +++++++++++++++++++ .../Pod/Classes/Util/DoricJSDispatcher.m | 4 +- 5 files changed, 133 insertions(+), 19 deletions(-) create mode 100644 doric-android/doric/src/main/java/pub/doric/utils/DoricJSDispatcher.java diff --git a/doric-android/doric/src/main/java/pub/doric/shader/ScrollerNode.java b/doric-android/doric/src/main/java/pub/doric/shader/ScrollerNode.java index 5472d176..7c153c75 100644 --- a/doric-android/doric/src/main/java/pub/doric/shader/ScrollerNode.java +++ b/doric-android/doric/src/main/java/pub/doric/shader/ScrollerNode.java @@ -24,12 +24,15 @@ import com.github.pengfeizhou.jscore.JSValue; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.Callable; import pub.doric.DoricContext; import pub.doric.DoricScrollChangeListener; import pub.doric.IDoricScrollable; +import pub.doric.async.AsyncResult; import pub.doric.extension.bridge.DoricMethod; import pub.doric.extension.bridge.DoricPlugin; +import pub.doric.utils.DoricJSDispatcher; import pub.doric.utils.DoricUtils; import pub.doric.widget.HVScrollView; @@ -45,6 +48,7 @@ public class ScrollerNode extends SuperNode implements IDoricScrol private Set listeners = new HashSet<>(); private String onScrollFuncId; private String onScrollEndFuncId; + private DoricJSDispatcher jsDispatcher = new DoricJSDispatcher(); public ScrollerNode(DoricContext doricContext) { @@ -69,15 +73,22 @@ public class ScrollerNode extends SuperNode implements IDoricScrol hvScrollView.setOnScrollChangeListener(new HVScrollView.OnScrollChangeListener() { @Override - public void onScrollChange(HVScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { + public void onScrollChange(HVScrollView v, final int scrollX, final int scrollY, int oldScrollX, int oldScrollY) { for (DoricScrollChangeListener listener : listeners) { listener.onScrollChange(v, scrollX, scrollY, oldScrollX, oldScrollY); } if (!TextUtils.isEmpty(onScrollFuncId)) { - callJSResponse(onScrollFuncId, new JSONBuilder() - .put("x", DoricUtils.px2dp(scrollX)) - .put("y", DoricUtils.px2dp(scrollY)) - .toJSONObject()); + if (!TextUtils.isEmpty(onScrollFuncId)) { + jsDispatcher.dispatch(new Callable() { + @Override + public AsyncResult call() throws Exception { + return callJSResponse(onScrollFuncId, new JSONBuilder() + .put("x", DoricUtils.px2dp(scrollX)) + .put("y", DoricUtils.px2dp(scrollY)) + .toJSONObject()); + } + }); + } } } diff --git a/doric-android/doric/src/main/java/pub/doric/shader/flowlayout/FlowLayoutNode.java b/doric-android/doric/src/main/java/pub/doric/shader/flowlayout/FlowLayoutNode.java index 84fa62a1..66f79f46 100644 --- a/doric-android/doric/src/main/java/pub/doric/shader/flowlayout/FlowLayoutNode.java +++ b/doric-android/doric/src/main/java/pub/doric/shader/flowlayout/FlowLayoutNode.java @@ -30,13 +30,16 @@ import com.github.pengfeizhou.jscore.JSValue; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.Callable; import pub.doric.DoricContext; import pub.doric.DoricScrollChangeListener; import pub.doric.IDoricScrollable; +import pub.doric.async.AsyncResult; import pub.doric.extension.bridge.DoricPlugin; import pub.doric.shader.SuperNode; import pub.doric.shader.ViewNode; +import pub.doric.utils.DoricJSDispatcher; import pub.doric.utils.DoricUtils; /** @@ -84,6 +87,7 @@ public class FlowLayoutNode extends SuperNode implements IDoricScr private Set listeners = new HashSet<>(); private String onScrollFuncId; private String onScrollEndFuncId; + private DoricJSDispatcher jsDispatcher = new DoricJSDispatcher(); public FlowLayoutNode(DoricContext doricContext) { super(doricContext); @@ -247,16 +251,21 @@ public class FlowLayoutNode extends SuperNode implements IDoricScr @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); - int offsetX = recyclerView.computeHorizontalScrollOffset(); - int offsetY = recyclerView.computeVerticalScrollOffset(); + final int offsetX = recyclerView.computeHorizontalScrollOffset(); + final int offsetY = recyclerView.computeVerticalScrollOffset(); for (DoricScrollChangeListener listener : listeners) { listener.onScrollChange(recyclerView, offsetX, offsetY, offsetX - dx, offsetY - dy); } if (!TextUtils.isEmpty(onScrollFuncId)) { - callJSResponse(onScrollFuncId, new JSONBuilder() - .put("x", DoricUtils.px2dp(offsetX)) - .put("y", DoricUtils.px2dp(offsetY)) - .toJSONObject()); + jsDispatcher.dispatch(new Callable() { + @Override + public AsyncResult call() throws Exception { + return callJSResponse(onScrollFuncId, new JSONBuilder() + .put("x", DoricUtils.px2dp(offsetX)) + .put("y", DoricUtils.px2dp(offsetY)) + .toJSONObject()); + } + }); } } diff --git a/doric-android/doric/src/main/java/pub/doric/shader/list/ListNode.java b/doric-android/doric/src/main/java/pub/doric/shader/list/ListNode.java index 8358e760..5a4a7946 100644 --- a/doric-android/doric/src/main/java/pub/doric/shader/list/ListNode.java +++ b/doric-android/doric/src/main/java/pub/doric/shader/list/ListNode.java @@ -30,13 +30,16 @@ import com.github.pengfeizhou.jscore.JSValue; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.Callable; import pub.doric.DoricContext; import pub.doric.DoricScrollChangeListener; import pub.doric.IDoricScrollable; +import pub.doric.async.AsyncResult; import pub.doric.extension.bridge.DoricPlugin; import pub.doric.shader.SuperNode; import pub.doric.shader.ViewNode; +import pub.doric.utils.DoricJSDispatcher; import pub.doric.utils.DoricUtils; /** @@ -57,6 +60,7 @@ public class ListNode extends SuperNode implements IDoricScrollabl private Set listeners = new HashSet<>(); private String onScrollFuncId; private String onScrollEndFuncId; + private DoricJSDispatcher jsDispatcher = new DoricJSDispatcher(); public ListNode(DoricContext doricContext) { super(doricContext); @@ -87,16 +91,21 @@ public class ListNode extends SuperNode implements IDoricScrollabl @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); - int offsetX = recyclerView.computeHorizontalScrollOffset(); - int offsetY = recyclerView.computeVerticalScrollOffset(); + final int offsetX = recyclerView.computeHorizontalScrollOffset(); + final int offsetY = recyclerView.computeVerticalScrollOffset(); for (DoricScrollChangeListener listener : listeners) { listener.onScrollChange(recyclerView, offsetX, offsetY, offsetX - dx, offsetY - dy); } if (!TextUtils.isEmpty(onScrollFuncId)) { - callJSResponse(onScrollFuncId, new JSONBuilder() - .put("x", DoricUtils.px2dp(offsetX)) - .put("y", DoricUtils.px2dp(offsetY)) - .toJSONObject()); + jsDispatcher.dispatch(new Callable() { + @Override + public AsyncResult call() throws Exception { + return callJSResponse(onScrollFuncId, new JSONBuilder() + .put("x", DoricUtils.px2dp(offsetX)) + .put("y", DoricUtils.px2dp(offsetY)) + .toJSONObject()); + } + }); } } diff --git a/doric-android/doric/src/main/java/pub/doric/utils/DoricJSDispatcher.java b/doric-android/doric/src/main/java/pub/doric/utils/DoricJSDispatcher.java new file mode 100644 index 00000000..e867b6b6 --- /dev/null +++ b/doric-android/doric/src/main/java/pub/doric/utils/DoricJSDispatcher.java @@ -0,0 +1,85 @@ +/* + * 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.utils; + +import android.os.Handler; +import android.os.Looper; + +import java.util.LinkedList; +import java.util.concurrent.Callable; + +import pub.doric.async.AsyncResult; + +/** + * @Description: pub.doric.utils + * @Author: pengfei.zhou + * @CreateDate: 2020-03-25 + */ +public class DoricJSDispatcher implements AsyncResult.Callback { + private LinkedList> blocks = new LinkedList<>(); + private boolean consuming = false; + private Handler mHandler = new Handler(Looper.getMainLooper()); + + public void dispatch(Callable block) { + if (blocks.size() > 0) { + blocks.clear(); + } + blocks.push(block); + if (!consuming) { + consume(); + } + } + + private void consume() { + Callable block = blocks.pollLast(); + if (block != null) { + consuming = true; + try { + AsyncResult result = block.call(); + result.setCallback(this); + } catch (Exception e) { + e.printStackTrace(); + consume(); + } + } else { + consuming = false; + } + } + + @Override + public void onResult(Object result) { + if (Looper.myLooper() == mHandler.getLooper()) { + consume(); + } else { + mHandler.post(new Runnable() { + @Override + public void run() { + consume(); + } + }); + } + } + + @Override + public void onError(Throwable t) { + + } + + @Override + public void onFinish() { + + } +} diff --git a/doric-iOS/Pod/Classes/Util/DoricJSDispatcher.m b/doric-iOS/Pod/Classes/Util/DoricJSDispatcher.m index f6dbe3ab..899a96f1 100644 --- a/doric-iOS/Pod/Classes/Util/DoricJSDispatcher.m +++ b/doric-iOS/Pod/Classes/Util/DoricJSDispatcher.m @@ -29,8 +29,8 @@ - (void)dispatch:(DoricAsyncResult *(^)(void))block { if (!self.blocks) { self.blocks = [@[block] mutableCopy]; } else { - while (self.blocks.count > 0) { - [self.blocks removeLastObject]; + if (self.blocks.count > 0) { + [self.blocks removeAllObjects]; } [self.blocks insertObject:block atIndex:0]; }