Flutter和音频播放器:无法停止在2个类之间播放音频

trnvg8h3  于 2023-02-05  发布在  Flutter
关注(0)|答案(3)|浏览(280)

你好
我是Flutter的新手,我希望你能理解我的问题。我正在使用"AudioPlayers",希望从定义的页面和类中播放音频,并且能够停止来自同一页面中另一个类的音乐。在我的代码中,如果我停留在同一个类中,一切都正常,但是一旦音频启动,我就切换到另一个类(通过链接),音频继续播放,停止按钮不起作用。下面是我的代码,我解释一下。
分为3类:
注意:这将是可能的,看看我们在哪个类,感谢appbar.
类1:2按钮,播放/暂停和停止这个类工作完美。当我点击停止音频停止,我们转到类2。
类2:2按钮也,播放/暂停和"到类3"播放/暂停按钮工作正常,当我点击"到类3"它也工作,音频继续播放,这也是我想要的,到目前为止一切顺利.
class 3 = 2个按钮,播放/暂停和停止,问题是停止按钮不起作用,它没有停止从class 2推出的奥迪
我能看到的是:

  • 只要这些按钮在同一个类中,它们就可以工作
  • 即使在更改类后音频仍继续播放
  • "停止"按钮只对在自己的类上启动的音频起作用。2如果音频是在另一个类上启动的,"停止"按钮就不起作用。

你能帮我解决这个问题吗?
如果你也有这个可能性,这是不太重要的解决:例如,我希望当我在类1中并且我点击停止按钮时,音频停止并且我切换到类2,类2音频自动开始,而不必点击播放按钮。
预先感谢你的帮助。
下面是完整的代码:**

import 'dart:typed_data';

import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';


class Class1 extends  StatefulWidget {
  @override
  State<Class1> createState() => _Class1State();
}

class _Class1State extends State<Class1> {

  int maxduration = 100;
  int currentpos = 0;
  String currentpostlabel = "00:00";
  String audioasset = "assets/audio/audio1.mp3";
  bool isplaying = false;
  bool audioplayed = false;
  late Uint8List audiobytes;

  AudioPlayer player = AudioPlayer();

  @override
  void initState() {
    Future.delayed(Duration.zero, () async {

      ByteData bytes = await rootBundle.load(audioasset); //load audio from assets
      audiobytes = bytes.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes);
      //convert ByteData to Uint8List

      player.onDurationChanged.listen((Duration d) { //get the duration of audio
        maxduration = d.inMilliseconds;
        setState(() {

        });
      });

      player.onAudioPositionChanged.listen((Duration  p){
        currentpos = p.inMilliseconds; //get the current position of playing audio

        //generating the duration label
        int shours = Duration(milliseconds:currentpos).inHours;
        int sminutes = Duration(milliseconds:currentpos).inMinutes;
        int sseconds = Duration(milliseconds:currentpos).inSeconds;

        int rhours = shours;
        int rminutes = sminutes - (shours * 60);
        int rseconds = sseconds - (sminutes * 60 + shours * 60 * 60);

        currentpostlabel = "$rhours:$rminutes:$rseconds";

        setState(() {
          //refresh the UI
        });
      });

    });
    super.initState();

  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            title: Text("Class1"),
            backgroundColor: Colors.blue
        ),
        body: Container(
            margin: EdgeInsets.only(top:50),
            child: Column(
              children: [

                Container(
                  child: Wrap(
                    spacing: 10,
                    children: [
                      ElevatedButton.icon(
                          onPressed: () async {
                            if(!isplaying && !audioplayed){
                              int result = await player.playBytes(audiobytes);
                              if(result == 1){ //play success
                                setState(() {
                                  isplaying = true;
                                  audioplayed = true;
                                });
                              }else{
                                print("Error while playing audio.");
                              }
                            }else if(audioplayed && !isplaying){
                              int result = await player.resume();
                              if(result == 1){ //resume success
                                setState(() {
                                  isplaying = true;
                                  audioplayed = true;
                                });
                              }else{
                                print("Error on resume audio.");
                              }
                            }else{
                              int result = await player.pause();
                              if(result == 1){ //pause success
                                setState(() {
                                  isplaying = false;
                                });
                              }else{
                                print("Error on pause audio.");
                              }
                            }
                          },
                          icon: Icon(isplaying?Icons.pause:Icons.play_arrow),
                          label:Text(isplaying?"Pause":"Play")
                      ),

                      ElevatedButton.icon(
                          onPressed: ()  {

                            setState(() {
                              Navigator.pushReplacement(
                                  context,
                                  PageRouteBuilder(
                                    pageBuilder: (context, animation1, animation2) => Class2(),
                                    transitionDuration: Duration.zero,
                                  )
                              );
                            });

                            setState(() async {
                              int result = await player.stop();
                              if(result == 1){ //stop success
                                setState(() {
                                  isplaying = false;
                                  audioplayed = false;
                                  currentpos = 0;
                                });
                              }else{
                                print("Error on stop audio.");
                              }
                            });

                          },
                          icon: Icon(Icons.stop),
                          label:Text("Stop")
                      ),


                    ],
                  ),
                )

              ],
            )

        )
    );
  }

}





class Class2 extends  StatefulWidget {
  @override
  State<Class2> createState() => _Class2State();
}

class _Class2State extends State<Class2> {

  int maxduration = 100;
  int currentpos = 0;
  String currentpostlabel = "00:00";
  String audioasset = "assets/audio/audio2.mp3";
  bool isplaying = false;
  bool audioplayed = false;
  late Uint8List audiobytes;

  AudioPlayer player = AudioPlayer();

  @override
  void initState() {
    Future.delayed(Duration.zero, () async {

      ByteData bytes = await rootBundle.load(audioasset); //load audio from assets
      audiobytes = bytes.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes);
      //convert ByteData to Uint8List

      player.onDurationChanged.listen((Duration d) { //get the duration of audio
        maxduration = d.inMilliseconds;
        setState(() {

        });
      });

      player.onAudioPositionChanged.listen((Duration  p){
        currentpos = p.inMilliseconds; //get the current position of playing audio

        //generating the duration label
        int shours = Duration(milliseconds:currentpos).inHours;
        int sminutes = Duration(milliseconds:currentpos).inMinutes;
        int sseconds = Duration(milliseconds:currentpos).inSeconds;

        int rhours = shours;
        int rminutes = sminutes - (shours * 60);
        int rseconds = sseconds - (sminutes * 60 + shours * 60 * 60);

        currentpostlabel = "$rhours:$rminutes:$rseconds";

        setState(() {
          //refresh the UI
        });
      });

    });

  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            title: Text("Class2"),
            backgroundColor: Colors.blueAccent
        ),
        body: Container(
            margin: EdgeInsets.only(top:50),
            child: Column(
              children: [

                Container(
                  child: Wrap(
                    spacing: 10,
                    children: [
                      ElevatedButton.icon(
                          onPressed: () async {
                            if(!isplaying && !audioplayed){
                              int result = await player.playBytes(audiobytes);
                              if(result == 1){ //play success
                                setState(() {
                                  isplaying = true;
                                  audioplayed = true;
                                });
                              }else{
                                print("Error while playing audio.");
                              }
                            }else if(audioplayed && !isplaying){
                              int result = await player.resume();
                              if(result == 1){ //resume success
                                setState(() {
                                  isplaying = true;
                                  audioplayed = true;
                                });
                              }else{
                                print("Error on resume audio.");
                              }
                            }else{
                              int result = await player.pause();
                              if(result == 1){ //pause success
                                setState(() {
                                  isplaying = false;
                                });
                              }else{
                                print("Error on pause audio.");
                              }
                            }
                          },
                          icon: Icon(isplaying?Icons.pause:Icons.play_arrow),
                          label:Text(isplaying?"Pause":"Play")
                      ),

                      ElevatedButton.icon(
                          onPressed: ()  {

                            setState(() {
                              Navigator.pushReplacement(
                                  context,
                                  PageRouteBuilder(
                                    pageBuilder: (context, animation1, animation2) => Class3(),
                                    transitionDuration: Duration.zero,
                                  )
                              );
                            });

                          },
                          icon: Icon(Icons.stop),
                          label:Text("To Class3")
                      ),

                    ],
                  ),
                )

              ],
            )

        )
    );
  }



}



class Class3 extends  StatefulWidget {
  @override
  State<Class3> createState() => _Class3State();
}

class _Class3State extends State<Class3> {

  int maxduration = 100;
  int currentpos = 0;
  String currentpostlabel = "00:00";
  String audioasset = "assets/audio/audio3.mp3";
  bool isplaying = false;
  bool audioplayed = false;
  late Uint8List audiobytes;

  AudioPlayer player = AudioPlayer();

  @override
  void initState() {
    Future.delayed(Duration.zero, () async {

      ByteData bytes = await rootBundle.load(audioasset); //load audio from assets
      audiobytes = bytes.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes);
      //convert ByteData to Uint8List

      player.onDurationChanged.listen((Duration d) { //get the duration of audio
        maxduration = d.inMilliseconds;
        setState(() {

        });
      });

      player.onAudioPositionChanged.listen((Duration  p){
        currentpos = p.inMilliseconds; //get the current position of playing audio

        //generating the duration label
        int shours = Duration(milliseconds:currentpos).inHours;
        int sminutes = Duration(milliseconds:currentpos).inMinutes;
        int sseconds = Duration(milliseconds:currentpos).inSeconds;

        int rhours = shours;
        int rminutes = sminutes - (shours * 60);
        int rseconds = sseconds - (sminutes * 60 + shours * 60 * 60);

        currentpostlabel = "$rhours:$rminutes:$rseconds";

        setState(() {
          //refresh the UI
        });
      });

    });
    super.initState();

  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            title: Text("Class3"),
            backgroundColor: Colors.blueGrey
        ),
        body: Container(
            margin: EdgeInsets.only(top:50),
            child: Column(
              children: [

                Container(
                  child: Wrap(
                    spacing: 10,
                    children: [
                      ElevatedButton.icon(
                          onPressed: () async {
                            if(!isplaying && !audioplayed){
                              int result = await player.playBytes(audiobytes);
                              if(result == 1){ //play success
                                setState(() {
                                  isplaying = true;
                                  audioplayed = true;
                                });
                              }else{
                                print("Error while playing audio.");
                              }
                            }else if(audioplayed && !isplaying){
                              int result = await player.resume();
                              if(result == 1){ //resume success
                                setState(() {
                                  isplaying = true;
                                  audioplayed = true;
                                });
                              }else{
                                print("Error on resume audio.");
                              }
                            }else{
                              int result = await player.pause();
                              if(result == 1){ //pause success
                                setState(() {
                                  isplaying = false;
                                });
                              }else{
                                print("Error on pause audio.");
                              }
                            }
                          },
                          icon: Icon(isplaying?Icons.pause:Icons.play_arrow),
                          label:Text(isplaying?"Pause":"Play")
                      ),


                      ElevatedButton.icon(
                          onPressed: ()  {

                            setState(() async {
                              int result = await player.stop();
                              if(result == 1){ //stop success
                                setState(() {
                                  isplaying = false;
                                  audioplayed = false;
                                  currentpos = 0;
                                });
                              }else{
                                print("Error on stop audio.");
                              }
                            });


                          },
                          icon: Icon(Icons.stop),
                          label:Text("Stop")
                      ),

                    ],
                  ),
                )

              ],
            )

        )
    );
  }



}
omtl5h9j

omtl5h9j1#

我相信停止按钮不工作的原因是由于每个类都有自己的音频播放器示例。这意味着他们不能与前一个类的播放器交互,以及为什么停止按钮不工作。
有几种方法可以解决这个问题。但是,查看示例中的代码,发现有很多重复的代码,并且不确定为什么需要三个类(没有完全阅读所有代码行)。一种解决方案是将AudioPlayer及其功能分离到它自己的类中,并在每个类中管理它的状态。本质上,只有一个AudioPlayer示例,所有类都可以在其中交互。

jm81lzqq

jm81lzqq2#

我不太确定你想在类3中实现什么。对于每个类,你都有彼此独立的音频播放器对象。因此它们的行为完全独立。我假设当你切换类时,音频仍然在播放,因为你没有调用来释放它。

@override
  void dispose() {
    player.dispose();
    super.dispose();
  }

除此之外,如果你想停止一个从另一个类开始的音频,你应该把对象传递给另一个类并使用它。

class Class3 extends  StatefulWidget {
final AudioPlayer player;
  const Class3 ({
  required this.player,
   Key? key
}) : super(key: key);

  @override
  State<Class3> createState() => _Class3State();
}

换课的时候:

Navigator.pushReplacement(
  context,
  PageRouteBuilder(
        pageBuilder: (context, animation1, animation2) => Class3(player),
                     ....

因此,这将把音频播放器从类2传递到类3,因此,可以从类3停止。

f5emj3cl

f5emj3cl3#

这可能不是答案,但我猜你已经在一个State类中声明了每个AudioPlayer示例。这是为了允许通过声明它们的原始类中的setState()来更改它们的状态。在原始State类之外的另一个类中示例化后,访问AudioPlayer状态或停止、播放等可能会很棘手。
它可以通过传递每个AudioPlayer示例(已经设置了音频路径)并将该示例传递给另一个类来播放它、停止它等来提供帮助。如果您需要将AudioPlayer示例列表传递给另一个类,则在通过onPress、onTap传递之前示例化该列表。
在状态类中按下:

onPressed: (){                                                                              
    setState((){                                                                                     
        t.playAudio(playerHandlerList, t.id!);                                                                                                       
    });
}

t是Track类的示例,并且已经声明了playerHandlerList(需要先设置List,如下所示)

List<PlayerHandlerObject> playerHandlerList = <PlayerHandlerObject>[];
playerHandlerList.add(new PlayerHandlerObject(t.file_path!, t.id!));

播放器处理程序对象:

class PlayerHandlerObject{
    AudioPlayer just_audio = new AudioPlayer(); //..Using Just_Audio package
    int track_id = -1;
    
    PlayerHandlerObject(String fp, int t_id){      
        track_id = t_id;
        just_audio.setFilePath(fp);
    }
}

playAudio在Track类中

class Track  {
    final int? id;
    final String? file_path;

    Track(
     {
      this.id, 
      this.file_path,  
     }    
    );

    Future<void> playAudio( List<PlayerHandlerObject> list , int t_id) async{         
        list.forEach((element) { 
            if (element.track_id == t_id){
                if (  element.just_audio.playing )  {
                    element.just_audio.stop();             
                }
                element.just_audio.play();  
            }  
        });
                                           
    }

    Future<void> stopAudio( List<PlayerHandlerObject> list, int t_id)  async {                   
        list.forEach((element) { 
            if (element.track_id == t_id){
                element.just_audio.stop();                         
            }  
        });                         
    }
}

您可以更改代码以使用索引列表来匹配音轨id和索引,这样就不需要比较id了。
此示例使用Just_Audio包。

相关问题