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

Flutter报错:'Future<dynamic>'不是'Widget'的子类型(flutter_tts)

Hey there! Let's break down your issues step by step—since you're new to Flutter's async/Future handling, I'll keep things clear and actionable.


1. Fixing the 'type 'Future<dynamic>' is not a subtype of type 'Widget'' Error

This error happens because Flutter's build() method must return a Widget synchronously, but you're accidentally returning a Future (from an async function) instead. The issue points to your DisplayPictureScreen, so let's fix that first.

What went wrong?

Chances are you tried to run an async task (like triggering voice playback) directly inside the build() method, which returns a Future instead of a proper Widget. Since build() gets called multiple times (e.g., when the screen rotates or state updates), this not only breaks the UI but also contributes to your repeated playback problem.

The fix:

Move async logic out of build() and into a place that runs only once (like initState() for StatefulWidgets) or use FutureBuilder if you need to wait for an async result before rendering UI.

Example StatefulWidget implementation:

import 'package:flutter/material.dart';
import 'package:flutter_tts/flutter_tts.dart';
import 'dart:io';

class DisplayPictureScreen extends StatefulWidget {
  final String imagePath;
  final String recognitionResult; // Pass your pre-detected result here

  const DisplayPictureScreen({
    super.key,
    required this.imagePath,
    required this.recognitionResult,
  });

  @override
  State<DisplayPictureScreen> createState() => _DisplayPictureScreenState();
}

class _DisplayPictureScreenState extends State<DisplayPictureScreen> {
  final FlutterTts _flutterTts = FlutterTts();

  @override
  void initState() {
    super.initState();
    // Trigger voice playback ONCE when the screen initializes
    _speakRecognitionResult();
  }

  Future<void> _speakRecognitionResult() async {
    // Stop any existing playback first to avoid overlaps
    await _flutterTts.stop();
    // Speak the detected result
    await _flutterTts.speak(widget.recognitionResult);
  }

  @override
  Widget build(BuildContext context) {
    // Build your UI normally—no async code here!
    return Scaffold(
      appBar: AppBar(title: const Text('货币识别结果')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Image.file(File(widget.imagePath)),
            const SizedBox(height: 20),
            Text('识别结果:${widget.recognitionResult}'),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    // Clean up TTS resources when the screen is closed to prevent leaks
    _flutterTts.stop();
    _flutterTts.dispose();
    super.dispose();
  }
}

2. Stopping Repeated Voice Playback & App Crashes

The repeated playback and crash are likely caused by two issues:

  • Playback being triggered multiple times (e.g., every time build() runs)
  • Unstopped audio tasks piling up in memory

Key fixes:

  1. Only trigger playback once: As shown above, use initState() to run playback logic once when the screen loads, not in build().
  2. Stop existing playback before speaking: Always call await _flutterTts.stop(); before speak() to cancel any ongoing audio, preventing overlapping playback.
  3. Clean up resources: Use the dispose() method to stop TTS and release resources when the screen is closed—this prevents memory leaks that lead to crashes.

Bonus: If you're doing real-time recognition

If your app continuously scans for currency (instead of one-time detection), add a debounce or flag to ensure playback only runs after a new, unique result is detected. For example:

String? _lastSpokenResult;

Future<void> _speakIfNewResult(String newResult) async {
  if (newResult != _lastSpokenResult) {
    await _flutterTts.stop();
    await _flutterTts.speak(newResult);
    _lastSpokenResult = newResult;
  }
}

Quick Async/Future Basics for Flutter Newbies

  • async marks a function as asynchronous (it will run in the background).
  • Future is like a "promise" that the function will eventually return a value (or finish running).
  • You can't return a Future from build()—Flutter needs a Widget right away. Use FutureBuilder if you need to wait for an async result to render UI, or run async tasks in initState()/button presses instead.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 17:02:34