Flutter同步调用插件synchronized_call的使用

发布于 1周前 作者 bupafengyu 来自 Flutter

Flutter同步调用插件synchronized_call的使用

synchronized_call 是一个用于在Flutter中同步调用异步函数的插件。它能够防止并发访问异步代码,节流和去抖动异步函数调用,并支持添加监听器以观察所有异步函数或BLoC是否已完成。

功能特点

  • 防止对异步代码的并发访问。
  • 节流和去抖动异步函数调用。
  • 支持添加监听器以观察所有异步函数/BLoC是否已完成。

示例

基本用法

考虑以下异步函数doWrite

import 'package:synchronized_call/synchronized_call.dart';

Future _writeBatch(List<int> indexes) async {
  for (var i in indexes) {
    await Future.delayed(Duration(microseconds: 1));
    print('$i');
  }
}

void doWrite() async {
  await _writeBatch([1, 2, 3, 4, 5]);
  print(' ');
}

直接调用三次doWrite

doWrite();
doWrite();
doWrite();

/// 输出:'111222333444555'
/// 期望输出:'12345 12345 12345'

使用synchronized_call包中的CallLock

BaseLock lock = CallLock.create();

lock.call(doWrite);
lock.call(doWrite);
lock.call(doWrite);

/// 输出将是期望的:'12345 12345 12345'

想要在所有BLoC执行完毕后接收回调:

lock.addListener(() {
  print('All bloc are done executed.');
});

另一种用法

将异步代码/BLoC放在await lock()unlock()方法之间:

Locker lock = Locker();

void do() async {
    await lock.lock();

    /// ...
    /// 其他异步或同步代码在这里...
    /// ...
    await doWrite();
    
    lock.unlock();
}

do();
do();
do();

/// 输出将是期望的:'12345 12345 12345'

完整示例Demo

以下是一个完整的示例程序,演示了如何使用不同的锁机制来确保异步函数按顺序执行:

import 'dart:async';
import 'dart:io';

import 'package:synchronized_call/synchronized_call.dart';

Future writeBatch(List<int> indexes) async {
  for (var i in indexes) {
    await Future.delayed(Duration(milliseconds: 100));
    stdout.write('$i');
  }
}

Future<int> doWrite() async {
  await writeBatch([1, 2, 3, 4, 5]);
  print('');
  return 0;
}

/// 测试 [SerialLock] 和 [SyncLock]
void main() async {
  int _count = 5;

  ///
  print('>>>>>>>>>> Not in sequence');
  for (int i = 0; i < _count; i++) {
    doWrite();
  }
  await Future.delayed(Duration(seconds: 3));

  ///
  print('>>>>>>>>>> Start [SerialLock] async test');
  BaseLock lock = CallLock.create();
  for (int i = 0; i < _count; i++) {
    lock.call(doWrite);
  }
  lock.addListener(() {
    print('>>>>>>>>>> Done [SerialLock] async test\n');
  });
  await Future.delayed(Duration(seconds: 3));

  ///
  print('>>>>>>>>>> Start [SerialLock] sync test, using Completer.sync()');
  BaseLock syncLock = CallLock.create(isSync: true);
  for (int i = 0; i < _count; i++) {
    syncLock.call(doWrite);
  }
  syncLock.addListener(() {
    print('>>>>>>>>>> Done [SerialLock] sync test\n');
  });
  await Future.delayed(Duration(seconds: 3));

  ///
  print('>>>>>>>>>> Start [SerialLock] test with name ~~~');
  for (int i = 0; i < _count; i++) {
    CallLock.get('__async_test__').call(doWrite);
  }
  CallLock.get('__async_test__').addListener(() {
    print('>>>>>>>>>> Done [SerialLock] test with name ~~~\n');
  });
  await Future.delayed(Duration(seconds: 3));

  ///
  print('>>>>>>>>>> Start [SyncLock] async test');
  CallLock.set('__async_lock__', SyncLock());
  for (int i = 0; i < _count; i++) {
    CallLock.get('__async_lock__').call(doWrite);
  }
  CallLock.get('__async_lock__').addListener(() {
    print('>>>>>>>>>> Done [SyncLock] async test\n');
  });
  await Future.delayed(Duration(seconds: 3));

  ///
  print('>>>>>>>>>> Start [SyncLock] sync test, using Completer.sync()');
  CallLock.set('__sync_lock__', SyncLock(isSync: true));
  for (int i = 0; i < _count; i++) {
    CallLock.get('__sync_lock__').call(doWrite);
  }
  CallLock.get('__sync_lock__').addListener(() {
    print('>>>>>>>>>> Done [SyncLock] sync test\n');
  });
  await Future.delayed(Duration(seconds: 3));
}

通过上述示例,你可以看到如何使用synchronized_call包来确保异步函数按顺序执行,并且可以添加监听器来观察所有异步操作是否完成。


更多关于Flutter同步调用插件synchronized_call的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter同步调用插件synchronized_call的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter开发中,synchronized_call 插件允许你在 Dart 代码和原生代码(如 iOS 的 Swift/Objective-C 和 Android 的 Kotlin/Java)之间进行同步调用。这对于需要在 Dart 和原生平台之间传递数据并立即得到结果的情况非常有用。

以下是如何在 Flutter 项目中使用 synchronized_call 插件的一个基本示例。这个示例展示了如何在 Dart 代码中调用原生方法并获取同步结果。

1. 添加依赖

首先,在你的 pubspec.yaml 文件中添加 synchronized_call 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  synchronized_call: ^最新版本号  # 请替换为实际的最新版本号

然后运行 flutter pub get 来获取依赖。

2. iOS 原生代码实现

如果你正在开发 iOS 应用,需要在 AppDelegate.swiftAppDelegate.m 中注册插件(如果使用的是 Swift,可能需要创建一个桥接头文件)。此外,你需要在原生代码中实现你需要同步调用的方法。

Swift 示例

ios/Runner/Runner-Bridging-Header.h 中添加:

#import <synchronized_call/SynchronizedCallPlugin.h>

然后,在 ios/Runner/AppDelegate.swift 中,确保 application:didFinishLaunchingWithOptions: 方法中包含插件注册代码(通常 Flutter 创建的项目已经包含这部分代码):

import UIKit
import Flutter
import synchronized_call

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    SynchronizedCallPlugin.register(with: self.registrar(forPlugin: "synchronized_call")!)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

接下来,在 ios/Classes 文件夹中创建一个新的 Swift 文件,比如 MyNativeMethods.swift,并实现你的原生方法:

import Foundation
import synchronized_call

class MyNativeMethods: NSObject, SynchronizedCallPluginDelegate {
    func synchronizedCallHandler(_ call: SynchronizedCallPlugin.Call, arguments: Any?, reply: @escaping (Any?) -> Void) {
        if let args = arguments as? [String: Any], let method = args["method"] as? String {
            switch method {
            case "sayHello":
                let result = "Hello from iOS!"
                reply(result)
            default:
                reply(nil)
            }
        } else {
            reply(nil)
        }
    }
}

// 在 AppDelegate 中注册这个类
// (通常这部分代码在 Flutter 插件自动生成的注册代码中已经完成,但这里为了完整性而展示)
// let myNativeMethods = MyNativeMethods()
// SynchronizedCallPlugin.setDelegate(myNativeMethods, forRegistrar: self.registrar(forPlugin: "synchronized_call")!)

注意:实际注册可能在 Flutter 插件的自动注册过程中已经完成,通常不需要手动注册。

3. Android 原生代码实现

在 Android 中,你需要在 MainActivity.ktMainActivity.java 中注册插件,并在原生代码中实现你需要的方法。

Kotlin 示例

android/app/src/main/kotlin/.../MainActivity.kt 中,确保包含插件注册代码(通常 Flutter 创建的项目已经包含这部分代码):

package com.example.yourapp

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
import synchronized_call.SynchronizedCallPlugin

class MainActivity: FlutterActivity() {
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        GeneratedPluginRegistrant.registerWith(flutterEngine)
        SynchronizedCallPlugin.registerWith(flutterEngine.dartExecutor.binaryMessenger)
    }
}

然后,在 android/app/src/main/kotlin/... 文件夹中创建一个新的 Kotlin 文件,比如 MyNativeMethods.kt,并实现你的原生方法:

package com.example.yourapp

import synchronized_call.SynchronizedCallPlugin
import synchronized_call.SynchronizedCallPlugin.Call

class MyNativeMethods : SynchronizedCallPlugin.Delegate {
    override fun onMethodCall(call: Call, arguments: Map<String, Any?>, reply: (Any?) -> Unit) {
        val method = arguments["method"] as? String
        when (method) {
            "sayHello" -> {
                val result = "Hello from Android!"
                reply(result)
            }
            else -> reply(null)
        }
    }
}

// 通常在 Flutter 插件的自动注册过程中已经完成注册,但这里为了完整性而展示如何手动注册(通常不需要)
// val myNativeMethods = MyNativeMethods()
// SynchronizedCallPlugin.setDelegate(myNativeMethods, flutterEngine.dartExecutor.binaryMessenger)

4. Dart 代码调用

最后,在你的 Dart 代码中,你可以使用 synchronized_call 插件来调用原生方法:

import 'package:flutter/material.dart';
import 'package:synchronized_call/synchronized_call.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Synchronized Call Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: _callNativeMethod,
            child: Text('Call Native Method'),
          ),
        ),
      ),
    );
  }

  Future<void> _callNativeMethod() async {
    final result = await SynchronizedCall.call<String>(
      'my_native_methods',  // 这里的字符串应该与原生代码中注册的 delegate 名称对应(如果有的话)
      arguments: <String, dynamic>{
        'method': 'sayHello',
      },
    );
    
    // 显示结果
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('Native Result: $result'),
      ),
    );
  }
}

请注意,SynchronizedCall.call 方法是异步的(使用了 asyncawait 关键字),尽管它内部可能实现了同步调用机制,但从 Dart 的角度来看,它仍然返回一个 Future。这是因为 Dart 的异步模型要求所有可能涉及 I/O 操作(包括平台通道通信)的函数都是异步的。

在实际使用中,你可能不需要关心它是同步还是异步,只需按照异步方式处理结果即可。如果你确实需要确保调用是同步的(从原生代码执行的角度来看),那么 synchronized_call 插件背后的机制已经为你处理了这些细节。

回到顶部