android:add JSDispatcher to optimize scrollchange callback

This commit is contained in:
pengfei.zhou 2020-03-25 13:48:58 +08:00 committed by osborn
parent 2b7ff95de6
commit 139a8775d4
5 changed files with 133 additions and 19 deletions

View File

@ -24,12 +24,15 @@ import com.github.pengfeizhou.jscore.JSValue;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import pub.doric.DoricContext; import pub.doric.DoricContext;
import pub.doric.DoricScrollChangeListener; import pub.doric.DoricScrollChangeListener;
import pub.doric.IDoricScrollable; import pub.doric.IDoricScrollable;
import pub.doric.async.AsyncResult;
import pub.doric.extension.bridge.DoricMethod; import pub.doric.extension.bridge.DoricMethod;
import pub.doric.extension.bridge.DoricPlugin; import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.utils.DoricJSDispatcher;
import pub.doric.utils.DoricUtils; import pub.doric.utils.DoricUtils;
import pub.doric.widget.HVScrollView; import pub.doric.widget.HVScrollView;
@ -45,6 +48,7 @@ public class ScrollerNode extends SuperNode<HVScrollView> implements IDoricScrol
private Set<DoricScrollChangeListener> listeners = new HashSet<>(); private Set<DoricScrollChangeListener> listeners = new HashSet<>();
private String onScrollFuncId; private String onScrollFuncId;
private String onScrollEndFuncId; private String onScrollEndFuncId;
private DoricJSDispatcher jsDispatcher = new DoricJSDispatcher();
public ScrollerNode(DoricContext doricContext) { public ScrollerNode(DoricContext doricContext) {
@ -69,16 +73,23 @@ public class ScrollerNode extends SuperNode<HVScrollView> implements IDoricScrol
hvScrollView.setOnScrollChangeListener(new HVScrollView.OnScrollChangeListener() { hvScrollView.setOnScrollChangeListener(new HVScrollView.OnScrollChangeListener() {
@Override @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) { for (DoricScrollChangeListener listener : listeners) {
listener.onScrollChange(v, scrollX, scrollY, oldScrollX, oldScrollY); listener.onScrollChange(v, scrollX, scrollY, oldScrollX, oldScrollY);
} }
if (!TextUtils.isEmpty(onScrollFuncId)) { if (!TextUtils.isEmpty(onScrollFuncId)) {
callJSResponse(onScrollFuncId, new JSONBuilder() if (!TextUtils.isEmpty(onScrollFuncId)) {
jsDispatcher.dispatch(new Callable<AsyncResult>() {
@Override
public AsyncResult call() throws Exception {
return callJSResponse(onScrollFuncId, new JSONBuilder()
.put("x", DoricUtils.px2dp(scrollX)) .put("x", DoricUtils.px2dp(scrollX))
.put("y", DoricUtils.px2dp(scrollY)) .put("y", DoricUtils.px2dp(scrollY))
.toJSONObject()); .toJSONObject());
} }
});
}
}
} }
@Override @Override

View File

@ -30,13 +30,16 @@ import com.github.pengfeizhou.jscore.JSValue;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import pub.doric.DoricContext; import pub.doric.DoricContext;
import pub.doric.DoricScrollChangeListener; import pub.doric.DoricScrollChangeListener;
import pub.doric.IDoricScrollable; import pub.doric.IDoricScrollable;
import pub.doric.async.AsyncResult;
import pub.doric.extension.bridge.DoricPlugin; import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.shader.SuperNode; import pub.doric.shader.SuperNode;
import pub.doric.shader.ViewNode; import pub.doric.shader.ViewNode;
import pub.doric.utils.DoricJSDispatcher;
import pub.doric.utils.DoricUtils; import pub.doric.utils.DoricUtils;
/** /**
@ -84,6 +87,7 @@ public class FlowLayoutNode extends SuperNode<RecyclerView> implements IDoricScr
private Set<DoricScrollChangeListener> listeners = new HashSet<>(); private Set<DoricScrollChangeListener> listeners = new HashSet<>();
private String onScrollFuncId; private String onScrollFuncId;
private String onScrollEndFuncId; private String onScrollEndFuncId;
private DoricJSDispatcher jsDispatcher = new DoricJSDispatcher();
public FlowLayoutNode(DoricContext doricContext) { public FlowLayoutNode(DoricContext doricContext) {
super(doricContext); super(doricContext);
@ -247,17 +251,22 @@ public class FlowLayoutNode extends SuperNode<RecyclerView> implements IDoricScr
@Override @Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy); super.onScrolled(recyclerView, dx, dy);
int offsetX = recyclerView.computeHorizontalScrollOffset(); final int offsetX = recyclerView.computeHorizontalScrollOffset();
int offsetY = recyclerView.computeVerticalScrollOffset(); final int offsetY = recyclerView.computeVerticalScrollOffset();
for (DoricScrollChangeListener listener : listeners) { for (DoricScrollChangeListener listener : listeners) {
listener.onScrollChange(recyclerView, offsetX, offsetY, offsetX - dx, offsetY - dy); listener.onScrollChange(recyclerView, offsetX, offsetY, offsetX - dx, offsetY - dy);
} }
if (!TextUtils.isEmpty(onScrollFuncId)) { if (!TextUtils.isEmpty(onScrollFuncId)) {
callJSResponse(onScrollFuncId, new JSONBuilder() jsDispatcher.dispatch(new Callable<AsyncResult>() {
@Override
public AsyncResult call() throws Exception {
return callJSResponse(onScrollFuncId, new JSONBuilder()
.put("x", DoricUtils.px2dp(offsetX)) .put("x", DoricUtils.px2dp(offsetX))
.put("y", DoricUtils.px2dp(offsetY)) .put("y", DoricUtils.px2dp(offsetY))
.toJSONObject()); .toJSONObject());
} }
});
}
} }

View File

@ -30,13 +30,16 @@ import com.github.pengfeizhou.jscore.JSValue;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import pub.doric.DoricContext; import pub.doric.DoricContext;
import pub.doric.DoricScrollChangeListener; import pub.doric.DoricScrollChangeListener;
import pub.doric.IDoricScrollable; import pub.doric.IDoricScrollable;
import pub.doric.async.AsyncResult;
import pub.doric.extension.bridge.DoricPlugin; import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.shader.SuperNode; import pub.doric.shader.SuperNode;
import pub.doric.shader.ViewNode; import pub.doric.shader.ViewNode;
import pub.doric.utils.DoricJSDispatcher;
import pub.doric.utils.DoricUtils; import pub.doric.utils.DoricUtils;
/** /**
@ -57,6 +60,7 @@ public class ListNode extends SuperNode<RecyclerView> implements IDoricScrollabl
private Set<DoricScrollChangeListener> listeners = new HashSet<>(); private Set<DoricScrollChangeListener> listeners = new HashSet<>();
private String onScrollFuncId; private String onScrollFuncId;
private String onScrollEndFuncId; private String onScrollEndFuncId;
private DoricJSDispatcher jsDispatcher = new DoricJSDispatcher();
public ListNode(DoricContext doricContext) { public ListNode(DoricContext doricContext) {
super(doricContext); super(doricContext);
@ -87,17 +91,22 @@ public class ListNode extends SuperNode<RecyclerView> implements IDoricScrollabl
@Override @Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy); super.onScrolled(recyclerView, dx, dy);
int offsetX = recyclerView.computeHorizontalScrollOffset(); final int offsetX = recyclerView.computeHorizontalScrollOffset();
int offsetY = recyclerView.computeVerticalScrollOffset(); final int offsetY = recyclerView.computeVerticalScrollOffset();
for (DoricScrollChangeListener listener : listeners) { for (DoricScrollChangeListener listener : listeners) {
listener.onScrollChange(recyclerView, offsetX, offsetY, offsetX - dx, offsetY - dy); listener.onScrollChange(recyclerView, offsetX, offsetY, offsetX - dx, offsetY - dy);
} }
if (!TextUtils.isEmpty(onScrollFuncId)) { if (!TextUtils.isEmpty(onScrollFuncId)) {
callJSResponse(onScrollFuncId, new JSONBuilder() jsDispatcher.dispatch(new Callable<AsyncResult>() {
@Override
public AsyncResult call() throws Exception {
return callJSResponse(onScrollFuncId, new JSONBuilder()
.put("x", DoricUtils.px2dp(offsetX)) .put("x", DoricUtils.px2dp(offsetX))
.put("y", DoricUtils.px2dp(offsetY)) .put("y", DoricUtils.px2dp(offsetY))
.toJSONObject()); .toJSONObject());
} }
});
}
} }
@Override @Override

View File

@ -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<Callable<AsyncResult>> blocks = new LinkedList<>();
private boolean consuming = false;
private Handler mHandler = new Handler(Looper.getMainLooper());
public void dispatch(Callable<AsyncResult> block) {
if (blocks.size() > 0) {
blocks.clear();
}
blocks.push(block);
if (!consuming) {
consume();
}
}
private void consume() {
Callable<AsyncResult> 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() {
}
}

View File

@ -29,8 +29,8 @@ - (void)dispatch:(DoricAsyncResult *(^)(void))block {
if (!self.blocks) { if (!self.blocks) {
self.blocks = [@[block] mutableCopy]; self.blocks = [@[block] mutableCopy];
} else { } else {
while (self.blocks.count > 0) { if (self.blocks.count > 0) {
[self.blocks removeLastObject]; [self.blocks removeAllObjects];
} }
[self.blocks insertObject:block atIndex:0]; [self.blocks insertObject:block atIndex:0];
} }