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回调暂时不能支持同步调用,现在都是异步的
相关推荐
Estar.Lee1 小时前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
温辉_xh1 小时前
uiautomator案例
android
工业甲酰苯胺2 小时前
MySQL 主从复制之多线程复制
android·mysql·adb
少说多做3433 小时前
Android 不同情况下使用 runOnUiThread
android·java
Estar.Lee4 小时前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
找藉口是失败者的习惯5 小时前
从传统到未来:Android XML布局 与 Jetpack Compose的全面对比
android·xml
Jinkey6 小时前
FlutterBasic - GetBuilder、Obx、GetX<Controller>、GetxController 有啥区别
android·flutter·ios
大白要努力!8 小时前
Android opencv使用Core.hconcat 进行图像拼接
android·opencv
天空中的野鸟8 小时前
Android音频采集
android·音视频
小白也想学C10 小时前
Android 功耗分析(底层篇)
android·功耗