You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter执行密钥生成函数时界面卡顿问题求助

解决Flutter密钥生成时UI卡顿的问题

你的问题出在CPU密集型的密钥生成逻辑跑在了主线程上,async/await没起作用是因为你的函数本质还是同步执行,只是套了async的壳而已。Flutter的主线程负责渲染UI,一旦被耗时计算阻塞,界面就会冻结。

解决方法是把耗时的密钥生成逻辑放到**Isolate(隔离区)**中执行——Isolate是Flutter的多线程实现,每个Isolate有独立的内存空间,不会阻塞主线程。Flutter 3.7+提供了Isolate.runAPI,用起来非常简洁。

修改后的完整代码

import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:web3dart/crypto.dart';
import 'package:web3dart/web3dart.dart';
import 'package:bip39/bip39.dart' as bip39;
import 'package:bip32/bip32.dart' as bip32;

// 把密钥生成逻辑放到顶层函数(Isolate需要可访问的函数)
Future<Credentials> _generateCredentialsInIsolate() async {
  String mnemonic = bip39.generateMnemonic();
  final seed = bip39.mnemonicToSeed(mnemonic);
  final masterNode = bip32.BIP32.fromSeed(seed);
  final bytesList = masterNode.privateKey;
  final String privateKey = bytesToHex(bytesList!);
  return EthPrivateKey.fromHex(privateKey);
}

class TestPage extends StatefulWidget {
  const TestPage({super.key});

  @override
  State<TestPage> createState() => _TestPageState();
}

class _TestPageState extends State<TestPage> {
  bool _isLoading = false;

  @override
  Widget build(BuildContext context) {
    return _isLoading
        ? const Center(child: CircularProgressIndicator())
        : Scaffold(
            body: Center(
              child: ElevatedButton(
                  onPressed: () async {
                    setState(() => _isLoading = true);
                    // 用Isolate.run执行耗时逻辑,不会阻塞主线程
                    Credentials myCredentials = await Isolate.run(_generateCredentialsInIsolate);
                    print(myCredentials.address);
                    setState(() => _isLoading = false);
                  },
                  child: const Text('Generate credentials')),
            ),
          );
  }
}

关键说明

  1. Isolate.run的作用:它会创建一个新的Isolate,在后台执行传入的函数,执行完成后把结果返回给主线程,全程不会阻塞UI。
  2. 函数提取:必须把耗时逻辑放到顶层函数或者静态函数中,因为Isolate无法访问State类的成员方法(Isolate有独立的上下文)。
  3. 参数传递:如果需要给Isolate传参数(比如自定义助记词),直接在_generateCredentialsInIsolate里加参数即可,Isolate.run支持传递可序列化的参数(比如String、int等基本类型)。

如果你的Flutter版本低于3.7,无法使用Isolate.run,可以用传统的Isolate.spawn方式,示例如下:

// 替代Isolate.run的实现
Future<Credentials> _generateCredentialsWithSpawn() async {
  final receivePort = ReceivePort();
  await Isolate.spawn(_isolateEntry, receivePort.sendPort);
  // 接收Isolate返回的结果
  final credentials = await receivePort.first as Credentials;
  receivePort.close();
  return credentials;
}

// Isolate的入口函数
void _isolateEntry(SendPort sendPort) {
  String mnemonic = bip39.generateMnemonic();
  final seed = bip39.mnemonicToSeed(mnemonic);
  final masterNode = bip32.BIP32.fromSeed(seed);
  final bytesList = masterNode.privateKey;
  final String privateKey = bytesToHex(bytesList!);
  final credentials = EthPrivateKey.fromHex(privateKey);
  // 把结果发送回主线程
  sendPort.send(credentials);
}

这样修改后,点击按钮时加载指示器会正常转动,界面不会卡顿,直到密钥生成完成后恢复正常。

内容的提问来源于stack exchange,提问作者O O

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:13:15