58fairDelegate方法调用规则-携带参数使用问题总结

本文继续记录fair界面的不同写法对fair delegate方法调用的处理的源码实现过程。 fair delegate

FairWidget界面解析2种正则匹配方式

在FairWidget 的build方法的界面解析过程 两种方式的写法将会走不同的流程。

  • GestureExpression

正则:

python 复制代码
RegExp(r'@(.+)', multiLine: false).hasMatch(exp ?? '');

将使用bindFunctionOf方法。

  • FunctionExpression

正则:

python 复制代码
RegExp(r'%(.+)', multiLine: false).hasMatch(exp ?? '');

将使用runFunctionOf 方法。

GestureExpression方式

这种方式为@(medalsInfoWidget) @开头的这种样式。

写法为:

css 复制代码
 Padding(
              padding: const EdgeInsets.symmetric(horizontal: 20),
              child: Builder(
                builder: medalsInfoWidget,
              ),
            ),
            
  Widget medalsInfoWidget(context) {
    return Container();
  }

他转化成json内容为:

css 复制代码
    {
              "className": "Padding",
              "na": {
                "padding": {
                  "className": "EdgeInsets.symmetric",
                  "na": {
                    "horizontal": 20
                  }
                },
                "child": {
                  "className": "Builder",
                  "na": {
                    "builder": "@(medalsInfoWidget)"
                  }
                }
              }
            },
            
             "medalsInfoWidget": {
      "className": "Container"
    }

JS文件中这种方式将不会有medalsInfoWidget js函数生成。

运行过程中: 将会匹配到GestureExpression 执行bindFunction逻辑:

kotlin 复制代码
dynamic bindFunctionOf(String funcName, ProxyMirror? proxyMirror,
    BindingData? bound, Domain? domain,
    {String? exp}) {
  if (_functions?[funcName] == null) {
    if (RegExp(r'.+(.+)', multiLine: false).hasMatch(funcName)) {
      var rFuncName = funcName.substring(0, funcName.indexOf('('));
      var params = funcName.substring(
          funcName.indexOf('(') + 1, funcName.lastIndexOf(')'));
      var args = params.split(',').map((e) {
        if (RegExp(r'^(index)', multiLine: false).hasMatch(e) &&
            domain is IndexDomain?) {
          return domain?.index;
        } else if (domain != null && domain.match(e)) {
          return domain.bindValue(e);
        } else {
          var r = proxyMirror?.evaluate(null, bound, e, domain: domain);
          if (r?.data == null) {
            return e;
          } else {
            return r?.data is ValueNotifier ? r?.data.value : r?.data;
          }
        }
      }).toList();
      return ([props]) {
        var arguments = [];
        if (props != null) {
          arguments.add(props);
        }
        if (args != null) {
          arguments.addAll(args);
        }
        _functions?['runtimeInvokeMethod']?.call(rFuncName, true, arguments);
      };
    } else {
      return ([props]) =>
          _functions?['runtimeInvokeMethod']?.call(funcName, false, props);
    }
  } else {
    return _functions?[funcName]; //因为我们实现了delegate 所以medalsInfoWidget 会执行delegate方法
  }
}

对应我们的代理方法实现为:

javascript 复制代码
  Map<String, Function> bindFunction() {
    var bindFunction = super.bindFunction();
    bindFunction.addAll({
 
      'medalsInfoWidget': _medalsInfoWidget,
 
    });
    return bindFunction;
  }


  Widget _medalsInfoWidget(context) { //这个context 不是从js传递过来的。是从build过程中获取传递的对应层的context
    //context
 
  }

整体的运行过程如下:

调用1:

调用2:

调用3:

调用4:

FunctionExpression 方式

这种方式为%(medalsInfoWidget2) %开头的这种样式。

Widget的写法为:

css 复制代码
   Padding(
              padding: const EdgeInsets.symmetric(horizontal: 20),
              child: medalsInfoWidget2(),
          
            ),
 
     // 不能写不支持的返回值类型,返回值不能是widget这种js不支持的类型。写返回值不会生成JS方法,也不会走delegate
  medalsInfoWidget2() {}

转化成json为

css 复制代码
    {
              "className": "Padding",
              "na": {
                "padding": {
                  "className": "EdgeInsets.symmetric",
                  "na": {
                    "horizontal": 20
                  }
                },
                "child": "%(medalsInfoWidget2)"
              }
            },

js方法为:

javascript 复制代码
     medalsInfoWidget2: function medalsInfoWidget2() {
                    const __thiz__ = this;
                    with(__thiz__) {}
                },

对应我们的代理方法实现为:

javascript 复制代码
  Map<String, Function> bindFunction() {
    var bindFunction = super.bindFunction();
    bindFunction.addAll({
 
      'medalsInfoWidget2': _medalsInfoWidget2,
    });
    return bindFunction;
  }

    Widget _medalsInfoWidget2() {
   
  }

运行过程中: 将会匹配到 FunctionExpression 执行 runFunctionOf 逻辑:

%(medalsInfoWidget2)执行 : dynamic runFunctionOf(String funcName, ProxyMirror? proxyMirror, BindingData? bound, Domain? domain, {String? exp})

ini 复制代码
 _functions?[funcName]?.call();
 

runFunctionOf完整实现为:

kotlin 复制代码
 
dynamic runFunctionOf(String funcName, ProxyMirror? proxyMirror,
    BindingData? bound, Domain? domain,
    {String? exp}) {
  if (_functions?[funcName] == null) {
    var result;
    if (RegExp(r'.+(.+)', multiLine: false).hasMatch(funcName)) {
      var rFuncName = funcName.substring(0, funcName.indexOf('('));
      var params = funcName.substring(
          funcName.indexOf('(') + 1, funcName.lastIndexOf(')'));
      var args = params.split(',').map((e) {
        if (RegExp(r'^(index)', multiLine: false).hasMatch(e) &&
            domain is IndexDomain?) {
          return domain?.index;
        } else if (domain != null && domain.match(e)) {
          return domain.bindValue(e);
        } else {
          var r = proxyMirror?.evaluate(null, bound, e, domain: domain);
          if (r?.data == null) {
            return e;
          } else {
            return r?.data is ValueNotifier ? r?.data.value : r?.data;
          }
        }
      }).toList();
      result = _functions?['runtimeInvokeMethodSync']?.call(rFuncName, args);
    } else {
      result = _functions?['runtimeInvokeMethodSync']?.call(funcName);
    }
    try {
      var value = jsonDecode(result);
      return value['result']['result'];
    } catch (e) {
      throw RuntimeError(errorMsg: result);
    }
  } else {
    return _functions?[funcName]?.call();//所以这里的delegate的方法也是不能支持携带参数
  }
} 

结论:

GestureExpression @开头的,bindFunctionOf 调用的 return _functions?[funcName];

还是匹配到 FunctionExpression % 开头的 runFunctionOf调用的 _functions?[funcName]?.call();

在执行时,delegate都是不支持带参数。

  • 所以遇到需要带参数时,需要用其他方法代替。

比如在delegate中 通过调用runtime?.variablesSync 和 runtime?.invokeMethodSync 获取js运行时的变量或者调用js函数。实例为:

csharp 复制代码
var invokeMethodSync = runtime?.variablesSync(pageName, {
  'medalsInfo': null,
  'noMedalsIcon': null,
  'noMedalsName': null,
});
var json = jsonDecode(invokeMethodSync!);
var result = json['result'];
 

或者调用

ini 复制代码
var invokeMethodSync =
    runtime?.invokeMethodSync(pageName, 'getScoreTip', null);
var json = jsonDecode(invokeMethodSync!);
var tip = json['result']['result'];
 
  • 使用jsPlugin。可以使用通过插件可以传递更多参数
  • js函数里没有办法再调用delegate了,可以用jsPlugin
  • delegate是fair一期的产物,原本就不支持传参。delegate要支持传参比较复杂
  • jsPlugin context不能传参,需要想办法内置到jsPlugin的dart部分
  • plugin回调暂时不能支持同步调用,现在都是异步的
相关推荐
无极程序员1 小时前
PHP常量
android·ide·android studio
萌面小侠Plus2 小时前
Android笔记(三十三):封装设备性能级别判断工具——低端机还是高端机
android·性能优化·kotlin·工具类·低端机
慢慢成长的码农2 小时前
Android Profiler 内存分析
android
大风起兮云飞扬丶2 小时前
Android——多线程、线程通信、handler机制
android
君蓦2 小时前
Flutter 本地存储与数据库的使用和优化
flutter
L72562 小时前
Android的Handler
android
清风徐来辽2 小时前
Android HandlerThread 基础
android
HerayChen3 小时前
HbuildderX运行到手机或模拟器的Android App基座识别不到设备 mac
android·macos·智能手机
顾北川_野3 小时前
Android 手机设备的OEM-unlock解锁 和 adb push文件
android·java