是否有一种方法在使用热重新启动时正确地配置资源:
热重启加载代码更改到VM,然后重新启动颤振应用程序,失去应用程序状态。( IntelliJ和Android中的⇧⌘\,VSCode中的⇧⌘F5 )
在我的应用程序中,我有一个很大的资源(这里是一个音频播放器),它是在initState上创建的,然后在dispose中处理。
当点击按钮时,它将开始播放一首歌:
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: const MyHomePage()));
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late AudioPlayer audioPlayer;
@override
void initState() {
print("Creating audio player");
audioPlayer = AudioPlayer();
super.initState();
}
@override
void dispose() {
print("Disposing audio player");
audioPlayer.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () async {
print("Starting new song");
final result = await audioPlayer.play(
'https://upload.wikimedia.org/wikipedia/commons/c/c2/Toccata_and_Fugue_in_D_Minor_%28ISRC_USUAN1100350%29.mp3',
);
await audioPlayer.resume();
print(result);
},
child: Icon(Icons.add),
),
);
}
}问题是当使用热重新启动时,不调用dispose方法,因此在热重新启动之前播放的歌曲不会停止,点击按钮将开始在最后一首歌曲的顶部播放另一首歌曲。
如果不调用dispose,那么在使用热重新启动时,如何正确地释放对象?
我的pubspec是默认的发布规范,添加了audioplayers依赖项:
name: flutter_application_1
description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: ">=2.16.0-10.0.dev <3.0.0"
dependencies:
flutter:
sdk: flutter
audioplayers: ^0.20.1
dev_dependencies:
flutter_test:
sdk: flutter发布于 2022-01-15 10:27:45
不幸的是,没有简单的方法来解决这个问题。
热-重新启动你的应用程序基本上就像杀死它的进程和重新启动它(用更新的代码),但实际上是本地进程被杀死了。这意味着,由于热重新启动而被杀死的应用程序不能执行任何清理代码(因此不等同于热重新加载的reassemble方法)。
不幸的是,平台插件没有通知热重启(颤振引擎中有一个打开的问题,您可以将其向上更新),所以它们也不能清理热重新启动应用程序获得的资源。
一个可能的解决办法是在应用程序启动时释放所有以前获得的资源。在第一次启动时,任何东西都不会被释放,因为热重启应用程序会从上一次运行中释放资源。不幸的是,audioplayers (和其他库,如flutter_sound)没有公开任何全局的"disposeAll“API。
所以,tl;dr,最好的解决方案是@PatrickMahomes提供的,添加一个开发时按钮,在重新启动之前停止播放器(或者忽略这个问题,因为它永远不会出现在发布版本中)。但是,如果你出于某种原因真的想这么做,这里有一个
我绝对不推荐实现的丑陋和疯狂的攻击:
在audioplayers中实现此功能的一种方法是将正在启动的plaing播放器的is (在启动时,而不是在应用程序被杀死时)保存到某个持久性存储中,在启动应用程序时读取它们(如上面所述),并在每个内存上调用AudioPlayer(playerId: id).release()。
发布于 2022-01-16 14:19:17
这个问题是由热重启动引起的,不能通知插件热重启。
这个解决方案只是针对您的特定情况的一个解决方案。
一旦您初始化了播放器,我就会保存玩家ID:
Future<AudioPlayer> _initPlayer() async {
print("Creating audio player");
SharedPreferences prefs = await SharedPreferences.getInstance();
final playerId = prefs.getString('audioPlayer');
if (playerId != null) {
AudioPlayer(playerId: playerId).release();
}
final audioPlayer = AudioPlayer();
await prefs.setString('audioPlayer', audioPlayer.playerId);
return audioPlayer;
}此函数使用SharedPreferences存储playerId。每次输入播放机时,这段代码都会检查存储的ID,如果有存储的ID,则会创建一个带有该ID的AudioPlayer并释放它。然后继续创建一个新的。
因为这个函数是异步的,所以它不能在initState()中运行。
我将FloatingActionButton封装在链接到_initPlayer()函数的FutureBuilder中。
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FutureBuilder(
future: _initPlayer(),
builder: (BuildContext context, AsyncSnapshot<AudioPlayer> snapshot) {
if (snapshot.hasData) {
audioPlayer = snapshot.data!;
return FloatingActionButton(
onPressed: () async {
print("Starting new song");
await audioPlayer.play(
'https://upload.wikimedia.org/wikipedia/commons/c/c2/Toccata_and_Fugue_in_D_Minor_%28ISRC_USUAN1100350%29.mp3',
);
},
child: const Icon(Icons.play_arrow),
);
}
return FloatingActionButton(
onPressed: () => {},
child: const CircularProgressIndicator(),
);
},
),
);
}https://stackoverflow.com/questions/69952232
复制相似问题