Flutter Analysis and Practice: Design of Lightweight Dynamic Rendering Engine

Image for post
Image for post

3.2.1 Background

3.2.2 Dynamic Solution

3.2.2.1 CodePush

3.2.2.2 Dynamic Template

3.2.3 Template Compilation

3.2.3.1 Template Specifications

Image for post
Image for post
Figure 3–6
@override
Widget build(BuildContext context) {
return new Container(
child: new Column(
children: <Widget>[
new MenuTitleWidget(data), // 头部
new Column( // 菜单栏
children: <Widget>[
new Row(
children: <Widget>[
new MenuItemWidget(data.menus[0]),
new MenuItemWidget(data.menus[1]),
new MenuItemWidget(data.menus[2]),
],
)
],
),
new Container( // 提示栏
child: new HintItemWidget(data.hints[0])),
],
),
);
}

3.2.3.2 Compilation Process

Image for post
Image for post
Figure 3–7
class ConstructorNode {
// 创建节点的名称
String constructorName;
// 参数列表
List<dynamic> argumentsList = <dynamic>[];
// 变量参数
Map<String, dynamic> arguments = <String, dynamic>{};
}
ArgumentList argumentList = astNode;for (Expression exp in argumentList.arguments) {
if (exp is NamedExpression) {
NamedExpression namedExp = exp;
final String name = ASTUtils.getNodeString(namedExp.name);
if (name == 'children') {
continue;
}
/// 是函数
if (namedExp.expression is FunctionExpression) {
currentNode.arguments[name] =
FunctionExpressionParser.parse(namedExp.expression);
} else {
/// 不是函数
currentNode.arguments[name] =
ASTUtils.getNodeString(namedExp.expression);
}
} else if (exp is PropertyAccess) {
PropertyAccess propertyAccess = exp;
final String name = ASTUtils.getNodeString(propertyAccess);
currentNode.argumentsList.add(name);
} else if (exp is StringInterpolation) {
StringInterpolation stringInterpolation = exp;
final String name = ASTUtils.getNodeString(stringInterpolation);
currentNode.argumentsList.add(name);
} else if (exp is IntegerLiteral) {
final IntegerLiteral integerLiteral = exp;
currentNode.argumentsList.add(integerLiteral.value);
} else {
final String name = ASTUtils.getNodeString(exp);
currentNode.argumentsList.add(name);
}
}

3.2.4 Rendering Engine

Image for post
Image for post
Figure 3–8

3.2.4.1 Template Obtaining

Image for post
Image for post
Figure 3–9

3.2.4.2 Widget Creation

Image for post
Image for post
Figure 3–10
Image for post
Image for post
Figure 3–11
/// 构建Widget用的参数
class WidgetCreateParam {
String constructorName; /// 构建的名称
dynamic context; /// 构建的上下文
Map<String, dynamic> arguments = <String, dynamic>{}; /// 字典参数
List<dynamic> argumentsList = <dynamic>[]; /// 列表参数
dynamic data; /// 原始数据
}

3.2.4.3 Event Processing

...
final List<dynamic> tList = <dynamic>[];
// 解析出参数列表
exp.argumentsList.forEach((dynamic arg) {
if (arg is String) {
final dynamic value = valueFromPath(arg, param.data);
if (value != null) {
tList.add(value);
} else {
tList.add(arg);
}
} else {
tList.add(arg);
}
});
// 找到对应的处理函数
final dynamic handler =
TeslaEventManager.sharedInstance().eventHandler(exp.actionName);
if (handler != null) {
handler(tList);
}
...

3.2.5 Final Effect

3.2.5.1 Frame Rate

Image for post
Image for post
Figure 3–12

3.2.5.2 Failure Rate

Original Source:

Follow me to keep abreast with the latest technology news, industry insights, and developer trends.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store