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

如何解决Flutter中TFLite的‘Interpreter busy’平台异常问题?

问题描述

我正在开发一款Android Flutter应用,使用TFLite的YOLOv5模型实现单类别实时检测。应用安装到设备后,运行2-3秒就会崩溃,抛出如下异常:

错误信息

E/flutter (16282): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(Failed to run model, Interpreter busy, java.lang.RuntimeException: Interpreter busy
E/flutter (16282):      at sq.flutter.tflite.TflitePlugin$TfliteTask.<init>(TflitePlugin.java:450)
E/flutter (16282):      at sq.flutter.tflite.TflitePlugin$RunModelOnFrame.<init>(TflitePlugin.java:545)
E/flutter (16282):      at sq.flutter.tflite.TflitePlugin.onMethodCall(TflitePlugin.java:117)
E/flutter (16282):      at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:258)
E/flutter (16282):      at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:295)
E/flutter (16282):      at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:322)
E/flutter (16282):      at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12)
E/flutter (16282):      at android.os.Handler.handleCallback(Handler.java:938)
E/flutter (16282):      at android.os.Handler.dispatchMessage(Handler.java:99)
E/flutter (16282):      at android.os.Looper.loop(Looper.java:236)
E/flutter (16282):      at android.app.ActivityThread.main(ActivityThread.java:7876)
E/flutter (16282):      at java.lang.reflect.Method.invoke(Native Method)
E/flutter (16282):      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
E/flutter (16282):      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
E/flutter (16282): , null)
E/flutter (16282): #0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:668:7)
E/flutter (16282): #1      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:315:18)
E/flutter (16282): <asynchronous suspension>
E/flutter (16282): #2      Tflite.runModelOnFrame (package:tflite/tflite.dart:73:12)
E/flutter (16282): <asynchronous suspension>
E/flutter (16282): #3      _HomeState.runModel (package:bat_app/Home.dart:43:25)
E/flutter (16282): <asynchronous suspension>
E/flutter (16282):
D/OOMEventManagerFK(16282): checkEventAndDumpForJE: 0
I/Process (16282): Sending signal. PID: 16282 SIG: 9
Lost connection to device.

我已经查看过StackOverflow上的相关解决方案,但都无效,为此问题耗费了5小时,求永久解决方案。

项目依赖(pubspec.yaml)

My dependencies are (pubspec.yaml):

name: bat_app
description: A new Flutter project.

publish_to: 'none' # Remove this line if you wish to publish to pub.dev


version: 1.0.0+1

environment:
  sdk: '>=2.16.1 <3.0.0'


dependencies:
  flutter:
    sdk: flutter
  
  tflite: ^1.1.2
  camera: ^0.10.3+2



  cupertino_icons: ^1.0.2

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^1.0.0

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

# The following section is specific to Flutter packages.
flutter:
  uses-material-design: true

  
  assets:
    - assets/
  

  # An image asset can refer to one or more resolution-specific "variants", see
  # https://flutter.dev/assets-and-images/#resolution-aware

  # For details regarding adding assets from package dependencies, see
  # https://flutter.dev/assets-and-images/#from-packages

  # To add custom fonts to your application, add a fonts section here,
  # in this "flutter" section. Each entry in this list should have a
  # "family" key with the font family name, and a "fonts" key with a
  # list giving the asset and other descriptors for the font. For
  # example:
  # fonts:
  #   - family: Schyler
  #     fonts:
  #       - asset: fonts/Schyler-Regular.ttf
  #       - asset: fonts/Schyler-Italic.ttf
  #         style: italic
  #   - family: Trajan Pro
  #     fonts:
  #       - asset: fonts/TrajanPro.ttf
  #       - asset: fonts/TrajanPro_Bold.ttf
  #         weight: 700
  #
  # For details regarding fonts from package dependencies,
  # see https://flutter.dev/custom-fonts/#from-packages

home.dart页面代码

My home.dart page code:

import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:tflite/tflite.dart';
import 'main.dart';

class Home extends StatefulWidget {
  const Home({Key? key}) : super(key: key);

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  CameraImage? cameraImage;
  CameraController? cameraController;
  String output = '';

  @override
  void initState() {
    super.initState();
    
    loadModel();
    loadCamera();
  }

  loadCamera() {
    cameraController = CameraController(cameras![0], ResolutionPreset.medium);
    cameraController!.initialize().then((value) {
      if (!mounted) {
        return;
      } else {
        setState(() {
          cameraController!.startImageStream((imageStream) {
            cameraImage = imageStream;
            runModel();
          });
        });
      }
    });
  }

  runModel() async {
    if (cameraImage != null) {
      var predictions = await Tflite.runModelOnFrame(
          bytesList: cameraImage!.planes.map((plane) {
            return plane.bytes;
          }).toList(),
          imageHeight: cameraImage!.height,
          imageWidth: cameraImage!.width,
          imageMean: 127.5,
          imageStd: 127.5,
          rotation: 90,
          numResults: 2,
          threshold: 0.6,
          asynch: true);

      predictions!.forEach((element) {
        setState(() {
          output = element['label'];
        });
      });
    }
  }

  loadModel() async {
    await Tflite.loadModel(
        model: "assets/model.tflite", labels: "assets/labels.txt");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Racket Bat Scoring'),
      ),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(20),
            child: Container(
              height: MediaQuery.of(context).size.height * 0.7,
              width: MediaQuery.of(context).size.width,
              child: !cameraController!.value.isInitialized
                  ? Container()
                  : AspectRatio(
                      aspectRatio: cameraController!.value.aspectRatio,
                      child: CameraPreview(cameraController!),
                    ),
            ),
          ),
          Text(output,
              style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20))
        ],
      ),
    );
  }
}
解决方案

核心问题

相机startImageStream会以约30fps的频率回调,每一次回调都触发runModel,但你使用的tflite插件的解释器是单实例单线程的,前一次模型推理还未完成,新的请求就已到达,直接导致Interpreter busy异常,最终因任务堆积引发崩溃。

具体修复步骤

1. 添加推理任务锁,避免并发调用

在_HomeState中添加布尔变量标记当前是否正在执行推理,确保同一时间只有一个推理任务运行:

class _HomeState extends State<Home> {
  CameraImage? cameraImage;
  CameraController? cameraController;
  String output = '';
  // 新增锁变量
  bool _isRunningInference = false;

  // ... 其他代码保持不变

2. 修改runModel方法,加入锁判断

更新runModel,仅当无推理任务时才执行模型调用:

runModel() async {
  // 若正在推理或无相机帧,直接返回
  if (cameraImage == null || _isRunningInference) {
    return;
  }
  
  _isRunningInference = true;
  try {
    var predictions = await Tflite.runModelOnFrame(
        bytesList: cameraImage!.planes.map((plane) {
          return plane.bytes;
        }).toList(),
        imageHeight: cameraImage!.height,
        imageWidth: cameraImage!.width,
        imageMean: 127.5,
        imageStd: 127.5,
        rotation: 90,
        numResults: 2,
        threshold: 0.6,
        asynch: true);

    if (predictions != null && predictions.isNotEmpty) {
      setState(() {
        output = predictions.first['label'];
      });
    }
  } finally {
    // 无论成功失败,都释放锁
    _isRunningInference = false;
  }
}

3. 优化相机帧处理(可选但推荐)

若无需30fps的实时推理,可降低帧处理频率,比如每2帧处理一次,减少推理压力:

class _HomeState extends State<Home> {
  // ... 其他变量
  int _frameCount = 0;

  // 修改loadCamera中的帧回调逻辑
  cameraController!.startImageStream((imageStream) {
    cameraImage = imageStream;
    _frameCount++;
    // 每2帧处理一次推理
    if (_frameCount % 2 == 0) {
      runModel();
    }
  });

4. 替换老旧tflite插件(推荐永久解决)

你当前使用的tflite: ^1.1.2是长期未维护的版本,官方推荐使用google_mlkit_object_detection或tflite_flutter插件,后者是官方维护的TFLite Flutter绑定,稳定性和性能更优:

  • 更新pubspec.yaml中的依赖:
dependencies:
  # 移除旧的tflite依赖
  # tflite: ^1.1.2
  tflite_flutter: ^0.10.1
  tflite_flutter_helper: ^0.4.0
  camera: ^0.10.3+2
  • 该插件支持多线程推理,能从根源上避免Interpreter busy问题。

5. 释放资源(避免内存泄漏)

在页面销毁时释放相机和TFLite资源:

@override
void dispose() {
  cameraController?.stopImageStream();
  cameraController?.dispose();
  Tflite.close();
  super.dispose();
}

验证修复

完成上述修改后重新运行应用,相机帧会被有序处理,不会再出现Interpreter busy异常,应用可稳定运行。


内容的提问来源于stack exchange,提问作者Md Mahadi Hasan Sany

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 18:24:58