【问题标题】:How to set PlayerState with flutter_bloc, audioplayers package Flutter如何用flutter_bloc设置PlayerState,audioplayers包Flutter
【发布时间】:2021-11-10 03:47:43
【问题描述】:

我正在使用这个包: https://pub.dev/packages/audioplayers

我有 2 个问题,首先是代码,当我按下 play 时音乐开始,但当我按下 stop 时它什么也不做,就好像我正在发出一个没有击中同一个 audioPlayer 的状态. 其次,我不知道如何更改 PlayerState,pad 中的播放器状态显示为 null,我认为我发出这些状态是错误的,有人可以以实际的方式告诉我这是正确的方式吗所以我学会了吗?因为我对flutter_bloc比较陌生。

集团

import 'dart:async';

import 'package:audioplayers/audioplayers.dart';
import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';

part 'audioplayersbloc_event.dart';
part 'audioplayersbloc_state.dart';

class AudioPlayersBloc
    extends Bloc<AudioPlayersBlocEvent, AudioPlayersBlocState> {
  AudioPlayersBloc() : super(AudioPlayersBlocState());

  String URL =
      '******'; // i put "***" because private url but its a mp3 file

  @override
  Stream<AudioPlayersBlocState> mapEventToState(
    AudioPlayersBlocEvent event,
  ) async* {
    if (event is OnPlayPlayerRemote) {
    PlayerState plyState;
  audioPlayersBloc.state.audioPlayer.onPlayerStateChanged.listen((event) 
  {
     plyState = event;
  });
     yield this.state.copyWith(audioPlayer: await this.playMusic(), 
     playerState: plyState);

    } else if (event is OnStopPlayer) {
      await this.stopMusic();
      yield this.state.copyWith(audioPlayer: await this.stopMusic());
    }
  }

  playMusic() async {

    await this.state.audioPlayer.play(URL);
  }

  pauseMusic() async {

    await this.state.audioPlayer.pause();

  }

  stopMusic() async {

    await this.state.audioPlayer.stop();
    
  }
}

状态

part of 'audioplayersbloc_bloc.dart';

class AudioPlayersBlocState {
  final AudioPlayer audioPlayer = AudioPlayer();
  final PlayerState playerState = PlayerState.PAUSED;
  final AudioCache audioCache = AudioCache();

  AudioPlayersBlocState(
      {AudioPlayer? audioPlayer,
      PlayerState? playerState,
      AudioCache? audioCache});

  AudioPlayersBlocState copyWith(
          {AudioPlayer? audioPlayer,
          PlayerState? playerState,
          AudioCache? audioCache}) =>
      AudioPlayersBlocState(
          audioPlayer: audioPlayer ?? this.audioPlayer,
          playerState: playerState ?? this.playerState,
          audioCache: audioCache ?? this.audioCache);
}

活动

part of 'audioplayersbloc_bloc.dart';

@immutable
abstract class AudioPlayersBlocEvent {}

class OnPlayPlayerRemote extends AudioPlayersBlocEvent {}


class OnStopPlayer extends AudioPlayersBlocEvent {}

我在首页播放音乐的按钮,只是一个按钮,是一个简单的播放器

IconButton(
                  icon: Icon(Icons.play_arrow),

                  onPressed: () {
                    context.read<AudioPlayersBloc>().add(OnPlayPlayerRemote());
                  },
                ),
                IconButton(
                  icon: Icon(Icons.stop),

                  onPressed: () {
                    context.read<AudioPlayersBloc>().add(OnStopPlayer());
                  },
                ),

【问题讨论】:

    标签: flutter audio flutter-bloc


    【解决方案1】:

    应该修复的第一种方法是保存 AudioPlayer、AudioCache 和 PlayerState。作为最佳实践,与业务逻辑相关的内容不应包含在状态对象中。在这种情况下,您将这些内容从 bloc 和 state 移动到您的屏幕(小部件)。

    注意:答案并未涵盖所有场景

    移动

    final AudioPlayer audioPlayer = AudioPlayer();
    final PlayerState playerState = PlayerState.PAUSED;
    final AudioCache audioCache = AudioCache();
    

    到主页。

    步骤:

    • 我们将添加一个 BlocConsumer 来启动/停止播放器。
    • 让适当的状态开始/停止
    • 编辑事件

    您可以通过here查看 BlocConsumer 的使用情况

    创建一个枚举来携带状态:

    enum PlayerState {playing, stopped}
    

    我们将在我们的集团状态中携带这些状态,例如:

    class AudioPlayersBlocState extends Equatable {
      PlayerState playerState;
    
      AudioPlayersBlocState({this.playerState});
    
      AudioPlayersBlocState copyWith(
              {PlayerState playerState}) =>
          AudioPlayersBlocState(playerState: playerState ?? this.playerState);
         
          @override
          List<Object> get props => [playerState];
    }
    

    现在,我们在状态上携带玩家状态,通过使用Equatable,我们的块现在可以知道何时更新状态,并将使其表现出色,因为如果没有任何变化,新传入的状态将不会更新视图。

    我们可以将事件更新为:

    @immutable
    abstract class AudioPlayersBlocEvent {}
    
    class PlayerStateChanged extends AudioPlayersBlocEvent {
        PlayerState playerState;
    
        PlayerStateChanged({this.playerState});
    }
    

    然后我们将产生新的状态结构:

    @override
      Stream<AudioPlayersBlocState> mapEventToState(
        AudioPlayersBlocEvent event,
      ) async* {
        if (event is PlayerStateChanged) {
            if (event.playerState == PlayerState.playing) {
                yield this.state.copyWith(playerState: PlayerState.playing);
            } else if (event.playerState == PlayerState.stopped) {
                yield this.state.copyWith(playerState: PlayerState.stopped);
            }
        }
      }
    

    我们还可以添加函数添加事件:

      playMusic() {
        add(PlayerStateChanged(playerState: PlayerState.playing));
      }
    
      stopMusic() {
        add(PlayerStateChanged(playerState: PlayerState.stopped));
      }
    

    那么我们应该像下面这样更新你的按钮:

    onPressed: () {
                        context.read<AudioPlayersBloc>().playMusic();
                      },
    

    接下来我们将反思这些变化的观点。 (我们将 AudioPlayer 放在屏幕上,我们可以在 bloc 中制作它,但为了简单起见,这样做了)

      BlocConsumer< AudioPlayersBloc, AudioPlayersBlocState >(
          listener: (context, state) {
        if (state.playerState == PlayerState.playing) {
            audioPlayer.play();
        } else if (state.playerState == PlayerState.stopped) {
            audioPlayer.stop();
        }
      },
      builder: (context, state) {
        // return a widget here based on Blocs's state
      }
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-23
      • 1970-01-01
      • 2021-03-26
      • 2023-01-22
      • 2020-02-16
      • 2020-04-08
      • 2020-10-12
      • 2020-12-08
      相关资源
      最近更新 更多