feat: add snapshot feature for devkit, this is for android

This commit is contained in:
pengfei.zhou 2021-07-09 17:16:30 +08:00 committed by osborn
parent 35b9d67de6
commit dbe94165b9
19 changed files with 500 additions and 7 deletions

View File

@ -45,5 +45,6 @@ public class MyApplication extends Application {
} }
}, intentFilter); }, intentFilter);
DoricRegistry.enablePerformance(true); DoricRegistry.enablePerformance(true);
DoricRegistry.enableRenderSnapshot(true);
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,212 @@
/*
* 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.devkit.ui;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.github.pengfeizhou.jscore.ArchiveException;
import com.github.pengfeizhou.jscore.JSArray;
import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JSObject;
import java.util.concurrent.Callable;
import pub.doric.DoricContext;
import pub.doric.async.AsyncResult;
import pub.doric.devkit.R;
import pub.doric.shader.RootNode;
import pub.doric.shader.ViewNode;
import pub.doric.utils.ThreadMode;
/**
* @Description: pub.doric.devkit.ui
* @Author: pengfei.zhou
* @CreateDate: 2021/7/9
*/
@SuppressLint("ViewConstructor")
public class DoricSnapshotView extends FrameLayout {
private int lastX;
private int lastY;
private final DoricContext doricContext;
private int snapNo = -1;
private int snapSize = 0;
private TextView snapIndex;
private ImageView spanPre;
private ImageView spanNext;
public DoricSnapshotView(@NonNull Context context, DoricContext doricContext) {
super(context);
this.doricContext = doricContext;
initView(context);
this.setAlpha(0.5f);
}
private void initView(Context context) {
LayoutInflater.from(context).inflate(R.layout.layout_doric_dev_view_snapshot, this);
snapIndex = findViewById(R.id.snap_idx);
spanPre = findViewById(R.id.snap_pre);
spanNext = findViewById(R.id.snap_next);
findViewById(R.id.snap_close).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
rollupSnapshot(snapSize);
((ViewGroup) (DoricSnapshotView.this.getParent())).removeView(DoricSnapshotView.this);
}
});
this.doricContext.callEntity("__renderSnapshotDepth__").setCallback(new AsyncResult.Callback<JSDecoder>() {
@Override
public void onResult(final JSDecoder result) {
snapIndex.post(new Runnable() {
@Override
public void run() {
try {
snapSize = result.decode().asNumber().toInt();
} catch (ArchiveException e) {
e.printStackTrace();
}
snapNo = snapSize;
rollupSnapshot(snapNo);
spanPre.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (snapNo <= 0) {
return;
}
snapNo--;
rollupSnapshot(snapNo);
}
});
spanNext.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (snapNo >= snapSize) {
return;
}
snapNo++;
rollupSnapshot(snapNo);
}
});
}
});
}
@Override
public void onError(Throwable t) {
}
@Override
public void onFinish() {
}
});
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offsetX = x - lastX;
int offsetY = y - lastY;
layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
break;
default:
break;
}
return true;
}
private void rollupSnapshot(int index) {
spanPre.setVisibility(index <= 0 ? View.INVISIBLE : View.VISIBLE);
spanNext.setVisibility(index >= snapSize ? View.INVISIBLE : View.VISIBLE);
snapIndex.setText(String.valueOf(index));
doricContext.callEntity("__restoreRenderSnapshot__", index).setCallback(new AsyncResult.Callback<JSDecoder>() {
@Override
public void onResult(JSDecoder result) {
try {
final JSArray jsArray = result.decode().asArray();
doricContext.getDriver().asyncCall(new Callable<Object>() {
@Override
public Object call() {
if (doricContext.getContext() instanceof Activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1
&& ((Activity) doricContext.getContext()).isDestroyed()) {
return null;
}
}
doricContext.getRootNode().getView().removeAllViews();
doricContext.getRootNode().clearSubModel();
for (int i = 0; i < jsArray.size(); i++) {
JSObject jsObject = jsArray.get(i).asObject();
String viewId = jsObject.getProperty("id").asString().value();
RootNode rootNode = doricContext.getRootNode();
if (TextUtils.isEmpty(rootNode.getId()) && "Root".equals(jsObject.getProperty("type").asString().value())) {
rootNode.setId(viewId);
rootNode.blend(jsObject.getProperty("props").asObject());
} else {
ViewNode viewNode = doricContext.targetViewNode(viewId);
if (viewNode != null) {
viewNode.blend(jsObject.getProperty("props").asObject());
}
}
}
return null;
}
}, ThreadMode.UI);
} catch (ArchiveException e) {
e.printStackTrace();
}
}
@Override
public void onError(Throwable t) {
}
@Override
public void onFinish() {
}
});
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="#ecf0f1"
android:gravity="center"
android:orientation="horizontal"
android:padding="15dp">
<ImageView
android:id="@+id/snap_pre"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/icon_doricdev_prev" />
<TextView
android:id="@+id/snap_idx"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:gravity="center"
android:text="1"
android:textColor="#000"
android:textSize="30dp" />
<ImageView
android:id="@+id/snap_next"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/icon_doricdev_next" />
<ImageView
android:id="@+id/snap_close"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="20dp"
android:src="@drawable/icon_doricdev_close" />
</LinearLayout>
</merge>

View File

@ -131,6 +131,9 @@ public class DoricContext {
} }
public void init(String initData) { public void init(String initData) {
if (DoricRegistry.isEnableRenderSnapshot()) {
callEntity("__enableSnapshot__");
}
this.extra = initData; this.extra = initData;
if (!TextUtils.isEmpty(initData)) { if (!TextUtils.isEmpty(initData)) {
callEntity(DoricConstant.DORIC_ENTITY_INIT, initData); callEntity(DoricConstant.DORIC_ENTITY_INIT, initData);

View File

@ -21,8 +21,6 @@ import android.util.Log;
import com.github.pengfeizhou.jscore.JSDecoder; import com.github.pengfeizhou.jscore.JSDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;

View File

@ -85,6 +85,8 @@ public class DoricRegistry {
private static boolean enablePerformance = false; private static boolean enablePerformance = false;
private static boolean enableRenderSnapshot = false;
public static void enablePerformance(boolean enable) { public static void enablePerformance(boolean enable) {
enablePerformance = enable; enablePerformance = enable;
} }
@ -93,6 +95,14 @@ public class DoricRegistry {
return enablePerformance; return enablePerformance;
} }
public static void enableRenderSnapshot(boolean enable) {
enableRenderSnapshot = enable;
}
public static boolean isEnableRenderSnapshot() {
return enableRenderSnapshot;
}
private static void initRegistry(DoricRegistry doricRegistry) { private static void initRegistry(DoricRegistry doricRegistry) {
for (DoricLibrary library : doricLibraries) { for (DoricLibrary library : doricLibraries) {
library.load(doricRegistry); library.load(doricRegistry);

View File

@ -1046,6 +1046,27 @@ var __values$3 = (undefined && undefined.__values) || function(o) {
}; } }; }
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}; };
var __read$2 = (undefined && undefined.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) { return o; }
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) { ar.push(r.value); }
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) { m.call(i); }
}
finally { if (e) { throw e.error; } }
}
return ar;
};
var __spreadArray$2 = (undefined && undefined.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
{ to[j] = from[i]; }
return to;
};
function NativeCall(target, propertyKey, descriptor) { function NativeCall(target, propertyKey, descriptor) {
var originVal = descriptor.value; var originVal = descriptor.value;
descriptor.value = function () { descriptor.value = function () {
@ -1061,6 +1082,8 @@ var Panel = /** @class */ (function () {
this.headviews = new Map; this.headviews = new Map;
this.onRenderFinishedCallback = []; this.onRenderFinishedCallback = [];
this.__rendering__ = false; this.__rendering__ = false;
this.snapshotEnabled = false;
this.renderSnapshots = [];
} }
Panel.prototype.onCreate = function () { }; Panel.prototype.onCreate = function () { };
Panel.prototype.onDestroy = function () { }; Panel.prototype.onDestroy = function () { };
@ -1183,7 +1206,19 @@ var Panel = /** @class */ (function () {
} }
}, undefined); }, undefined);
}; };
Panel.prototype.__renderSnapshotDepth__ = function () {
return this.renderSnapshots.length;
};
Panel.prototype.__restoreRenderSnapshot__ = function (idx) {
return __spreadArray$2([], __read$2(this.renderSnapshots)).slice(0, idx);
};
Panel.prototype.__enableSnapshot__ = function () {
this.snapshotEnabled = true;
};
Panel.prototype.nativeRender = function (model) { Panel.prototype.nativeRender = function (model) {
if (this.snapshotEnabled) {
this.renderSnapshots.push(JSON.parse(JSON.stringify(model)));
}
return this.context.callNative("shader", "render", model); return this.context.callNative("shader", "render", model);
}; };
Panel.prototype.hookBeforeNativeCall = function () { Panel.prototype.hookBeforeNativeCall = function () {
@ -1378,6 +1413,24 @@ var Panel = /** @class */ (function () {
__metadata$b("design:paramtypes", [Array, String]), __metadata$b("design:paramtypes", [Array, String]),
__metadata$b("design:returntype", void 0) __metadata$b("design:returntype", void 0)
], Panel.prototype, "__response__", null); ], Panel.prototype, "__response__", null);
__decorate$b([
NativeCall,
__metadata$b("design:type", Function),
__metadata$b("design:paramtypes", []),
__metadata$b("design:returntype", void 0)
], Panel.prototype, "__renderSnapshotDepth__", null);
__decorate$b([
NativeCall,
__metadata$b("design:type", Function),
__metadata$b("design:paramtypes", [Number]),
__metadata$b("design:returntype", void 0)
], Panel.prototype, "__restoreRenderSnapshot__", null);
__decorate$b([
NativeCall,
__metadata$b("design:type", Function),
__metadata$b("design:paramtypes", []),
__metadata$b("design:returntype", void 0)
], Panel.prototype, "__enableSnapshot__", null);
return Panel; return Panel;
}()); }());

View File

@ -825,6 +825,8 @@ class Panel {
this.headviews = new Map; this.headviews = new Map;
this.onRenderFinishedCallback = []; this.onRenderFinishedCallback = [];
this.__rendering__ = false; this.__rendering__ = false;
this.snapshotEnabled = false;
this.renderSnapshots = [];
} }
onCreate() { } onCreate() { }
onDestroy() { } onDestroy() { }
@ -933,7 +935,19 @@ class Panel {
} }
}, undefined); }, undefined);
} }
__renderSnapshotDepth__() {
return this.renderSnapshots.length;
}
__restoreRenderSnapshot__(idx) {
return [...this.renderSnapshots].slice(0, idx);
}
__enableSnapshot__() {
this.snapshotEnabled = true;
}
nativeRender(model) { nativeRender(model) {
if (this.snapshotEnabled) {
this.renderSnapshots.push(JSON.parse(JSON.stringify(model)));
}
return this.context.callNative("shader", "render", model); return this.context.callNative("shader", "render", model);
} }
hookBeforeNativeCall() { hookBeforeNativeCall() {
@ -1065,6 +1079,24 @@ __decorate$b([
__metadata$b("design:paramtypes", [Array, String]), __metadata$b("design:paramtypes", [Array, String]),
__metadata$b("design:returntype", void 0) __metadata$b("design:returntype", void 0)
], Panel.prototype, "__response__", null); ], Panel.prototype, "__response__", null);
__decorate$b([
NativeCall,
__metadata$b("design:type", Function),
__metadata$b("design:paramtypes", []),
__metadata$b("design:returntype", void 0)
], Panel.prototype, "__renderSnapshotDepth__", null);
__decorate$b([
NativeCall,
__metadata$b("design:type", Function),
__metadata$b("design:paramtypes", [Number]),
__metadata$b("design:returntype", void 0)
], Panel.prototype, "__restoreRenderSnapshot__", null);
__decorate$b([
NativeCall,
__metadata$b("design:type", Function),
__metadata$b("design:paramtypes", []),
__metadata$b("design:returntype", void 0)
], Panel.prototype, "__enableSnapshot__", null);
/* /*
* Copyright [2019] [Doric.Pub] * Copyright [2019] [Doric.Pub]

View File

@ -2346,6 +2346,8 @@ class Panel {
this.headviews = new Map; this.headviews = new Map;
this.onRenderFinishedCallback = []; this.onRenderFinishedCallback = [];
this.__rendering__ = false; this.__rendering__ = false;
this.snapshotEnabled = false;
this.renderSnapshots = [];
} }
onCreate() { } onCreate() { }
onDestroy() { } onDestroy() { }
@ -2454,7 +2456,19 @@ class Panel {
} }
}, undefined); }, undefined);
} }
__renderSnapshotDepth__() {
return this.renderSnapshots.length;
}
__restoreRenderSnapshot__(idx) {
return [...this.renderSnapshots].slice(0, idx);
}
__enableSnapshot__() {
this.snapshotEnabled = true;
}
nativeRender(model) { nativeRender(model) {
if (this.snapshotEnabled) {
this.renderSnapshots.push(JSON.parse(JSON.stringify(model)));
}
return this.context.callNative("shader", "render", model); return this.context.callNative("shader", "render", model);
} }
hookBeforeNativeCall() { hookBeforeNativeCall() {
@ -2586,6 +2600,24 @@ __decorate$b([
__metadata$b("design:paramtypes", [Array, String]), __metadata$b("design:paramtypes", [Array, String]),
__metadata$b("design:returntype", void 0) __metadata$b("design:returntype", void 0)
], Panel.prototype, "__response__", null); ], Panel.prototype, "__response__", null);
__decorate$b([
NativeCall,
__metadata$b("design:type", Function),
__metadata$b("design:paramtypes", []),
__metadata$b("design:returntype", void 0)
], Panel.prototype, "__renderSnapshotDepth__", null);
__decorate$b([
NativeCall,
__metadata$b("design:type", Function),
__metadata$b("design:paramtypes", [Number]),
__metadata$b("design:returntype", void 0)
], Panel.prototype, "__restoreRenderSnapshot__", null);
__decorate$b([
NativeCall,
__metadata$b("design:type", Function),
__metadata$b("design:paramtypes", []),
__metadata$b("design:returntype", void 0)
], Panel.prototype, "__enableSnapshot__", null);
/* /*
* Copyright [2019] [Doric.Pub] * Copyright [2019] [Doric.Pub]

View File

@ -31,6 +31,11 @@ export declare abstract class Panel {
private __onEnvChanged__; private __onEnvChanged__;
private __response__; private __response__;
private retrospectView; private retrospectView;
private snapshotEnabled;
private renderSnapshots;
private __renderSnapshotDepth__;
private __restoreRenderSnapshot__;
private __enableSnapshot__;
private nativeRender; private nativeRender;
private hookBeforeNativeCall; private hookBeforeNativeCall;
private hookAfterNativeCall; private hookAfterNativeCall;

View File

@ -40,6 +40,8 @@ export class Panel {
this.headviews = new Map; this.headviews = new Map;
this.onRenderFinishedCallback = []; this.onRenderFinishedCallback = [];
this.__rendering__ = false; this.__rendering__ = false;
this.snapshotEnabled = false;
this.renderSnapshots = [];
} }
onCreate() { } onCreate() { }
onDestroy() { } onDestroy() { }
@ -148,7 +150,19 @@ export class Panel {
} }
}, undefined); }, undefined);
} }
__renderSnapshotDepth__() {
return this.renderSnapshots.length;
}
__restoreRenderSnapshot__(idx) {
return [...this.renderSnapshots].slice(0, idx);
}
__enableSnapshot__() {
this.snapshotEnabled = true;
}
nativeRender(model) { nativeRender(model) {
if (this.snapshotEnabled) {
this.renderSnapshots.push(JSON.parse(JSON.stringify(model)));
}
return this.context.callNative("shader", "render", model); return this.context.callNative("shader", "render", model);
} }
hookBeforeNativeCall() { hookBeforeNativeCall() {
@ -280,3 +294,21 @@ __decorate([
__metadata("design:paramtypes", [Array, String]), __metadata("design:paramtypes", [Array, String]),
__metadata("design:returntype", void 0) __metadata("design:returntype", void 0)
], Panel.prototype, "__response__", null); ], Panel.prototype, "__response__", null);
__decorate([
NativeCall,
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], Panel.prototype, "__renderSnapshotDepth__", null);
__decorate([
NativeCall,
__metadata("design:type", Function),
__metadata("design:paramtypes", [Number]),
__metadata("design:returntype", void 0)
], Panel.prototype, "__restoreRenderSnapshot__", null);
__decorate([
NativeCall,
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], Panel.prototype, "__enableSnapshot__", null);

View File

@ -168,8 +168,29 @@ export abstract class Panel {
} }
}, undefined) }, undefined)
} }
private snapshotEnabled = false
private renderSnapshots: Model[] = []
@NativeCall
private __renderSnapshotDepth__() {
return this.renderSnapshots.length
}
@NativeCall
private __restoreRenderSnapshot__(idx: number) {
return [...this.renderSnapshots].slice(0, idx)
}
@NativeCall
private __enableSnapshot__() {
this.snapshotEnabled = true
}
private nativeRender(model: Model) { private nativeRender(model: Model) {
if (this.snapshotEnabled) {
this.renderSnapshots.push(JSON.parse(JSON.stringify(model)))
}
return this.context.callNative("shader", "render", model) return this.context.callNative("shader", "render", model)
} }

View File

@ -2400,6 +2400,8 @@ class Panel {
this.headviews = new Map; this.headviews = new Map;
this.onRenderFinishedCallback = []; this.onRenderFinishedCallback = [];
this.__rendering__ = false; this.__rendering__ = false;
this.snapshotEnabled = false;
this.renderSnapshots = [];
} }
onCreate() { } onCreate() { }
onDestroy() { } onDestroy() { }
@ -2508,7 +2510,19 @@ class Panel {
} }
}, undefined); }, undefined);
} }
__renderSnapshotDepth__() {
return this.renderSnapshots.length;
}
__restoreRenderSnapshot__(idx) {
return [...this.renderSnapshots].slice(0, idx);
}
__enableSnapshot__() {
this.snapshotEnabled = true;
}
nativeRender(model) { nativeRender(model) {
if (this.snapshotEnabled) {
this.renderSnapshots.push(JSON.parse(JSON.stringify(model)));
}
return this.context.callNative("shader", "render", model); return this.context.callNative("shader", "render", model);
} }
hookBeforeNativeCall() { hookBeforeNativeCall() {
@ -2640,6 +2654,24 @@ __decorate$b([
__metadata$b("design:paramtypes", [Array, String]), __metadata$b("design:paramtypes", [Array, String]),
__metadata$b("design:returntype", void 0) __metadata$b("design:returntype", void 0)
], Panel.prototype, "__response__", null); ], Panel.prototype, "__response__", null);
__decorate$b([
NativeCall,
__metadata$b("design:type", Function),
__metadata$b("design:paramtypes", []),
__metadata$b("design:returntype", void 0)
], Panel.prototype, "__renderSnapshotDepth__", null);
__decorate$b([
NativeCall,
__metadata$b("design:type", Function),
__metadata$b("design:paramtypes", [Number]),
__metadata$b("design:returntype", void 0)
], Panel.prototype, "__restoreRenderSnapshot__", null);
__decorate$b([
NativeCall,
__metadata$b("design:type", Function),
__metadata$b("design:paramtypes", []),
__metadata$b("design:returntype", void 0)
], Panel.prototype, "__enableSnapshot__", null);
/* /*
* Copyright [2019] [Doric.Pub] * Copyright [2019] [Doric.Pub]

File diff suppressed because one or more lines are too long