当我停止使用功能播放歌曲并更改导航栏索引时,颤动的音乐继续播放
Posted
技术标签:
【中文标题】当我停止使用功能播放歌曲并更改导航栏索引时,颤动的音乐继续播放【英文标题】:flutter music keeps playing when I stop playing song with function and change navigation bar index 【发布时间】:2021-02-07 06:47:33 【问题描述】:我有一个包含每个项目的音乐的列表。如果我关闭屏幕,我会更改当前位于的BottomNavigationPage
的index
并调用停止函数来停止音频,但这有时不起作用。如果歌曲正在加载过程中或用户速度非常快,歌曲将继续在不同的页面上播放。
我正在使用https://pub.dev/packages/audioplayers 插件。
这是我的缩小代码示例完整工作演示: 编辑::
所以我跟进了@Ringil 的提示,提供了一个完整的工作示例以及我在这里面临的实际问题。这是我的代码:
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main()
runApp(MyApp());
class MyApp extends StatelessWidget
// This widget is the root of your application.
@override
Widget build(BuildContext context)
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
class MyHomePage extends StatefulWidget
@override
_MyHomePageState createState() => _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
int currentIndex =0;
@override
Widget build(BuildContext context)
// Page selector for tab list
void _selectPage(int index)
print('page index: $index');
setState(()
currentIndex = index;
);
// Routes list for tab navigation android
final List<Widget> _pages = [
ScreenA(),
ScreenB(func: _selectPage),
];
return Scaffold(
appBar: AppBar(),
body: _pages[currentIndex],
bottomNavigationBar: SafeArea(
child: BottomNavigationBar(
onTap: _selectPage,
iconSize: 22,
currentIndex: currentIndex,
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.description),
label: 'ScreenA',
),
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.ac_unit_outlined),
label: 'ScreenB'),
],
),
),
);
class ScreenA extends StatelessWidget
@override
Widget build(BuildContext context)
return Container(
child: Text('HOME'),
);
class ScreenB extends StatefulWidget
Function func;
ScreenB(Key key, @required this.func) : super(key: key);
@override
_ScreenBState createState() => _ScreenBState();
class _ScreenBState extends State<ScreenB>
var audioPlayer = AudioPlayer(playerId: 'player');
var audioIndex = 0;
var audioFiles = [
"https://docs.google.com/uc?export=open&id=1SaJWqfQuHnFtL7uqrzfYG31hzOnqDM3r",
"https://docs.google.com/uc?export=open&id=1FZkFMjQyWguAl0RMAsYDEZ07c_Qf7gjz",
"https://docs.google.com/uc?export=open&id=1GqrwQ3eRuiil0p-Na_R1tMAvggp9YrbH",
];
var _controller = PageController();
@override
void initState()
super.initState();
// starting player
startPlayer();
startPlayer()
play();
// Player play class set globalindex
Future<void> play() async
int result = await audioPlayer.play(audioFiles[audioIndex]);
if (result == 1)
// success
// Stop song instance of player
Future<void> stop() async
int result = await audioPlayer.stop();
if (result == 1)
// success
// disposing listener if not needed or users navigates away from
@override
void dispose()
super.dispose();
audioPlayer.dispose();
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.access_alarm_sharp),
onPressed: () async
await stop();
widget.func(0);
,
),
],
),
body: PageView.custom(
dragStartBehavior: DragStartBehavior.start,
controller: _controller,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
childrenDelegate: SliverChildBuilderDelegate((ctx, pageIndex) =>
GestureDetector(
onPanUpdate: (details) async
if (details.delta.dx < 0)
_controller.nextPage(
duration: Duration(milliseconds: 200),
curve: Curves.easeInOut);
await stop();
setState(()
audioIndex = pageIndex;
play();
);
,
child: Center(
child: Container(
width: 200,
height: 200,
color: Colors.red,
child: Text(audioFiles[audioIndex])))))),
);
还有一段短视频展示了这个问题。如果我们转到轮播屏幕,在加载之前浏览已播放的歌曲并关闭屏幕,它们将在我不想要的不同屏幕上播放。我也不想以某种方式“阻止”用户滑动扔旋转木马,直到加载歌曲。 视频:https://streamable.com/e/ycxwob
基本上,我将我的代码压缩到尽可能少的程度。我拿了 Ringil 的代码,因为在他的演示中一切都很好。然后我添加了越来越多的代码,直到我再次注意到错误。现在我们到了。基本上,来自 hin 和 mine 的示例音频文件有所不同。从文件大小方面来看,我的文件并不大,但它们似乎更长,这给了我们一直期待的延迟。似乎如果在关闭或更改索引之前未加载歌曲,则会发生错误。
【问题讨论】:
我认为总会有一些(轻微的)延迟。您希望音频关闭多快? 【参考方案1】:听起来您正在尝试构建一个轮播滑块。我建议不要尝试构建它,而是使用 carousel_slider 包之类的东西。您应该可以在 onPageChanged
的回调中调用 play
。
但是,回到您的具体问题,我认为问题在于您可能使页面索引和 globalSongIndex
不同步。
您似乎在全球范围内有这样的事情:
var audioIndex = 0;
var audioFiles = [
"1.mp3",
"2.mp3",
"3.mp3"
];
具有这样的播放功能:
Future<void> play() async
int result = await audioPlayer.play(audioFiles[audioIndex]);
然后,为了确保您的手势和您的 pageView 控制器上的 pageView 同步,您需要确保当您在 PageController
上调用 nextPage
函数时,您还需要确保您的状态变量也更新为 nextPage
价值。我不太确定 Provider.of<Songs>
的具体细节是如何工作的,但您可能需要将其强制为特定值。
SliverChildBuilderDelegate((ctx, pageIndex) => GestureDetector(
onPanUpdate: (details) async
if (details.delta.dx < 0)
_controller.nextPage(
duration: Duration(milliseconds: 200),
curve: Curves.easeInOut);
await stop();
setState(()
audioIndex = pageIndex;
play();
);
,
child: Center(child: Text(audioFiles[audioIndex])))
完整的工作示例:
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main()
runApp(MyApp());
class MyApp extends StatelessWidget
// This widget is the root of your application.
@override
Widget build(BuildContext context)
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
class MyHomePage extends StatefulWidget
MyHomePage(Key key, this.title) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
var audioPlayer = AudioPlayer(playerId: 'player');
var audioIndex = 0;
var audioFiles = [
"https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
"https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3",
"https://www.soundhelix.com/examples/mp3/SoundHelix-Song-3.mp3"
];
var _controller = PageController();
@override
void initState()
super.initState();
// starting player
startPlayer();
startPlayer()
play();
// Player play class set globalindex
Future<void> play() async
int result = await audioPlayer.play(audioFiles[audioIndex]);
if (result == 1)
// success
// Stop song instance of player
Future<void> stop() async
int result = await audioPlayer.stop();
if (result == 1)
// success
// disposing listener if not needed or users navigates away from
@override
void dispose()
super.dispose();
audioPlayer.dispose();
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: PageView.custom(
dragStartBehavior: DragStartBehavior.start,
controller: _controller,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
childrenDelegate:
SliverChildBuilderDelegate((ctx, pageIndex) => GestureDetector(
onPanUpdate: (details) async
if (details.delta.dx < 0)
_controller.nextPage(
duration: Duration(milliseconds: 200),
curve: Curves.easeInOut);
await stop();
setState(()
audioIndex = pageIndex;
play();
);
,
child: Center(child: Text(audioFiles[audioIndex]))))));
【讨论】:
你好@Ringil,非常感谢你的代码。你完全正确,我的代码看起来几乎就像你描述的那样。现在我的问题,正如您在我的代码中看到的,用户可以随时使用 stop() 调用 IconButton;功能。现在,当我在加载歌曲之前执行此操作时,它并没有像我们预期的那样停止。结果是用户“关闭”或更改了页面,歌曲没有停止,只是将在不同的屏幕上播放,这不应该发生。我错过了什么?如果您能帮助我,将不胜感激。 @MarcelDz 不清楚navigationBarIndex.currentIndex = 0
应该做什么。 0
是什么意思,音频小部件是否使用不同的索引?
我怀疑另一件事是你可能没有await
stop
函数。
感谢您的回答。使用 navigationBarIndex.currentIndex = 0 我只是导航到第一个 BottomNavigationBar 项。我们也可以只使用 Navigator.of(context).pushnamed('page') 代替。如果我将 Iconbutton 更改为 await stop 和 Navigator 并将其设置为异步,则没有任何区别。即使我们等待停止功能,音乐也会在不同的屏幕上播放,这不应该发生。 (我可以确认我使用与示例中完全相同的结构,我也使用相同的功能,仍然是同样的问题)
如果您在示例中放置一个图标按钮,该按钮将具有停止功能并导航到不同的屏幕,如果您在轮播中滑动然后按关闭它,您应该能够实际重现错误图标按钮【参考方案2】:
添加:“与 WidgetsBindingObserver”
class Screen extends StatefulWidget with WidgetsBindingObserver
您将可以访问应用生命周期状态:
void didChangeAppLifecycleState(AppLifecycleState state)
if (state == AppLifecycleState.paused)
player.pause();
【讨论】:
您好,谢谢您的回答。如果我在我的应用程序中移动到不同的导航点,应用程序生命周期状态不会暂停,正如我在文档中阅读的那样。如果您最小化应用程序,将触发暂停。在我的情况下,我在屏幕 A 中,然后我通过单击下一个底部导航点移动到屏幕 B,即使我在移动到其他屏幕之前调用了 player.pause(),音乐仍然在屏幕 B 上播放。但我不会在那里最小化应用程序。以上是关于当我停止使用功能播放歌曲并更改导航栏索引时,颤动的音乐继续播放的主要内容,如果未能解决你的问题,请参考以下文章