如何在Flutter中缓存自定义Widget?

问题描述 投票:0回答:1

我正在 Dart 中编写 ChatApp,在使用以下方法编写自定义语音消息小部件时发现了一个问题:

audio_waveforms: ^1.0.5
我已经这样做了,但我没有找到一种方法来缓存语音消息小部件,这会导致加载时间很长,当您发送新的语音消息时,它会刹车,它会创建一条新消息,但它包含上面的消息和只有在您重新渲染聊天页面后,它才会自行纠正。这是代码:

import 'dart:async';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';

class AudioMessageBeta extends StatefulWidget {
  final String id;
  final String audioUrl;
  final String message;
  const AudioMessageBeta(
      {super.key,
      required this.audioUrl,
      required this.message,
      required this.id});

  @override
  State<AudioMessageBeta> createState() => _AudioMessageBetaState();
}

class _AudioMessageBetaState extends State<AudioMessageBeta> {
  bool isLoading = false;
  final PlayerController playerController = new PlayerController();
  StreamSubscription<PlayerState>? playerStateSubsription;

  Future<dynamic> downloadFile(String url) async {
    String dir = (await getApplicationDocumentsDirectory()).path;
    if (await File("$dir/${widget.id}.mp3").exists()) {
      return "$dir/${widget.id}.mp3";
    } else {
      File file = File("$dir/${widget.id}.mp3");
      var request = await http.get(
        Uri.parse(url),
      );
      var bytes = request.bodyBytes;
      await file.writeAsBytes(bytes);
      return file.path;
    }
  }

  void prepareVoice() async {
    await playerController.preparePlayer(
        path: await downloadFile(widget.audioUrl),
        shouldExtractWaveform: true,
        noOfSamples: (MediaQuery.of(context).size.width * 0.5) ~/ 5);
  }

  @override
  void initState() {
    isLoading = true;
    Future.delayed(const Duration(milliseconds: 200), () {
      prepareVoice();
      playerStateSubsription =
          playerController.onPlayerStateChanged.listen((PlayerState) {
        setState(() {});
      });
    });
    super.initState();
    isLoading = false;
  }

  @override
  void dispose() {
    if (mounted) {
      playerController.dispose();
      playerStateSubsription!.cancel();
    }
    super.dispose();
  }

  void playVoice() async {
    switch (playerController.playerState) {
      case PlayerState.playing:
        await playerController.pausePlayer();
        break;
      default:
        await playerController.startPlayer(finishMode: FinishMode.pause);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      constraints: BoxConstraints(
        maxWidth: MediaQuery.of(context).size.width * 0.75,
      ),
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 10),
        child: ListTile(
          contentPadding: const EdgeInsets.all(0),
          horizontalTitleGap: 8,
          leading: GestureDetector(
            onTap: () => playVoice(),
            child: SizedBox(
              height: 45,
              width: 45,
              child: CircleAvatar(
                backgroundColor: Theme.of(context).colorScheme.background,
                child: isLoading
                    ? const CircularProgressIndicator()
                    : Icon(playerController.playerState.isPlaying
                        ? Icons.pause_rounded
                        : Icons.play_arrow),
              ),
            ),
          ),
          title: Padding(
            padding: const EdgeInsets.symmetric(vertical: 5),
            child: AudioFileWaveforms(
              size: Size(MediaQuery.of(context).size.width * 0.5, 25),
              playerController: playerController,
              enableSeekGesture: true,
              continuousWaveform: false,
              waveformType: WaveformType.fitWidth,
              playerWaveStyle: PlayerWaveStyle(
                fixedWaveColor: Theme.of(context).colorScheme.background,
                liveWaveColor: Colors.white,
                spacing: 5,
                waveThickness: 2.5,
                scaleFactor: 200,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

我尝试了几种方法,但我无法让它工作,我也是 Flutter 的新手。

flutter dart caching
1个回答
0
投票

您应该将密钥传递给小部件;它防止了元素树、部件树和渲染对象树之间发生的冲突。

例如:

AudioMessageBeta(
key: ValueKey(id),
audioUrl: 'your_audio_url',
message: 'your_message'
),

这些资源将帮助您加深对该主题的理解:

https://abhishekdoshi26.medium.com/deep-dive-into-flutter-trees-542f7395df5c https://www.youtube.com/watch?v=kn0EOS-ZiIc&ab_channel=GoogleforDevelopers https://medium.com/@yetesfadev/understanding-keys-in-dart-and-flutter-use-cases-examples-advantages-and-disadvantages-efff26b2d6e8

© www.soinside.com 2019 - 2024. All rights reserved.