gpt4 book ai didi

Flutter 保存并恢复 AudioPlayer 位置

转载 作者:行者123 更新时间:2023-12-05 06:56:25 27 4
gpt4 key购买 nike

我在 flutter 中使用 audioplayers 库,我试图保存和恢复播放器位置,除了从第一个位置播放,就像缓存播放器搜索栏位置一样,在这段代码中,我尝试使用 SharedPreference 保存和恢复它,但我的实现不成功

class ApplicationSettings {
ApplicationSettings(StreamingSharedPreferences preferences)
: showIntro = preferences.getBool('showIntro', defaultValue: false),
pageViewIndex = preferences.getInt('pageViewIndex', defaultValue: 0),
audioPosition = preferences.getString('audioPosition', defaultValue: "{}")
;

final Preference<bool> showIntro;
final Preference<int> pageViewIndex;
final Preference<String> audioPosition;
}

AudioInformation 类:

part'audio_information.g.dart';

@JsonSerializable(nullable: true)
class AudioInformation {
final String productName;
final int audioPosition;

AudioInformation(this.productName, this.audioPosition);

factory AudioInformation.fromJson(Map<String, dynamic> json) => _$AudioInformationFromJson(json);

Map<String, dynamic> toJson() => _$AudioInformationToJson(this);
}

PlayerWidget 类:

enum PlayerState { stopped, playing, paused }
enum PlayingRouteState { speakers, earpiece }

class PlayerWidget extends StatefulWidget {
final String url;
final PlayerMode mode;
final String productName;
final String imageUrl;

PlayerWidget({Key key, @required this.url, this.mode = PlayerMode.MEDIA_PLAYER, @required this.productName, @required this.imageUrl}) : super(key: key);

@override
State<StatefulWidget> createState() {
return _PlayerWidgetState(url, mode);
}
}

class _PlayerWidgetState extends State<PlayerWidget> {
_PlayerWidgetState(this.url, this.mode);

String url;
PlayerMode mode;

AudioPlayer _audioPlayer;
Duration _duration;
Duration _position;

PlayerState _playerState = PlayerState.stopped;
PlayingRouteState _playingRouteState = PlayingRouteState.speakers;
StreamSubscription _durationSubscription;
StreamSubscription _positionSubscription;
StreamSubscription _playerCompleteSubscription;
StreamSubscription _playerErrorSubscription;
StreamSubscription _playerStateSubscription;
StreamSubscription<PlayerControlCommand> _playerControlCommandSubscription;

get _isPlaying => _playerState == PlayerState.playing;

get _isPaused => _playerState == PlayerState.paused;

get _durationText => _duration?.toString()?.split('.')?.first ?? '';

get _positionText => _position?.toString()?.split('.')?.first ?? '';

Preference<String> _audioPosition;

@override
void didChangeDependencies() {
super.didChangeDependencies();
_audioPosition = Provider.of<ApplicationSettings>(context).audioPosition;
}

@override
void initState() {
super.initState();
_initAudioPlayer();
_play();
}

@override
void dispose() {
_audioPlayer.dispose();
_durationSubscription?.cancel();
_positionSubscription?.cancel();
_playerCompleteSubscription?.cancel();
_playerErrorSubscription?.cancel();
_playerStateSubscription?.cancel();
_playerControlCommandSubscription?.cancel();
super.dispose();
}

@override
Widget build(BuildContext context) {
return PreferenceBuilder(
preference: _audioPosition,
builder: (context, String audioDetail) {

/* SAVE position*/
AudioInformation _audio = AudioInformation('${widget.productName}', _duration?.inMilliseconds?.round()??0);
_audioPosition.setValue(_audio.toJson().toString());

return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(Icons.audiotrack_outlined),
Expanded(
child: Text(
' - ${widget.productName}',
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
],
),
),
body: Stack(
children: [
Positioned.fill(
child: CachedNetworkImage(
imageUrl: widget.imageUrl,
fit: BoxFit.cover,
)),
Container(
width: double.infinity,
height: double.infinity,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 2.0, sigmaY: 2.0),
child: Container(
color: Colors.white.withOpacity(0.7),
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.all(16.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(11.0),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.2), offset: Offset(0.0, 0.0), spreadRadius: 1.0)],
border: Border.all(color: Colors.black)),
child: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: CachedNetworkImage(
imageUrl: '${widget.imageUrl}',
fit: BoxFit.cover,
width: 150.0,
),
),
),
Container(
margin: EdgeInsets.all(8.0),
padding: EdgeInsets.all(5.0),
decoration: BoxDecoration(color: Colors.white.withOpacity(0.5), border: Border.all(color: Colors.black), borderRadius: BorderRadius.circular(5.0)),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(
key: Key('play_button'),
onPressed: _isPlaying ? null : () => _play(),
iconSize: 64.0,
icon: Icon(MdiIcons.playCircle),
color: Colors.black,
),
IconButton(
key: Key('pause_button'),
onPressed: _isPlaying ? () => _pause() : null,
iconSize: 64.0,
icon: Icon(MdiIcons.pauseCircle),
color: Colors.green[900],
),
IconButton(
key: Key('stop_button'),
onPressed: _isPlaying || _isPaused ? () => _stop() : null,
iconSize: 64.0,
icon: Icon(MdiIcons.stopCircle),
color: Colors.indigo[700],
),
],
),
Slider(
onChanged: (v) {
final position = v * _duration.inMilliseconds;
_audioPlayer.seek(Duration(milliseconds: position.round()));

/* SAVE position*/
AudioInformation _audio = AudioInformation('${widget.productName}', position.round());
_audioPosition.setValue(_audio.toJson().toString());
},
value: (_position != null && _duration != null && _position.inMilliseconds > 0 && _position.inMilliseconds < _duration.inMilliseconds)
? _position.inMilliseconds / _duration.inMilliseconds
: 0.0,
),
],
),
),
_durationText != null && _durationText.toString().isNotEmpty
? Container(
height: 43.0,
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(color: Colors.white.withOpacity(0.5), border: Border.all(color: Colors.black), borderRadius: BorderRadius.circular(5.0)),
child: Text(
_position != null
? '${_positionText ?? ''} / ${_durationText ?? ''}'
: _duration != null
? _durationText
: ' --- ',
style: TextStyle(fontSize: 24.0),
),
)
: Container(
height: 43.0,
),
],
),
],
),
);
});
}

void _initAudioPlayer() {
_audioPlayer = AudioPlayer(mode: mode);
_durationSubscription = _audioPlayer.onDurationChanged.listen((duration) {
setState(() => _duration = duration);
});

_positionSubscription = _audioPlayer.onAudioPositionChanged.listen((p) => setState(() {
_position = p;
}));

_playerCompleteSubscription = _audioPlayer.onPlayerCompletion.listen((event) {
_onComplete();
setState(() {
_position = _duration;
});
});

_playerErrorSubscription = _audioPlayer.onPlayerError.listen((msg) {
print('audioPlayer error : $msg');
setState(() {
_playerState = PlayerState.stopped;
_duration = Duration(seconds: 0);
_position = Duration(seconds: 0);
});
});

_playerControlCommandSubscription = _audioPlayer.onPlayerCommand.listen((command) {
print('command');
});

_audioPlayer.onPlayerStateChanged.listen((state) {
if (!mounted) return;
});

_audioPlayer.onNotificationPlayerStateChanged.listen((state) {
if (!mounted) return;
//setState(() => _audioPlayerState = state);
});

_playingRouteState = PlayingRouteState.speakers;
}

Future<int> _play() async {
final playPosition = (_position != null && _duration != null && _position.inMilliseconds > 0 && _position.inMilliseconds < _duration.inMilliseconds) ? _position : null;
final result = await _audioPlayer.play(url, position: playPosition);
if (result == 1) setState(() => _playerState = PlayerState.playing);

_audioPlayer.setPlaybackRate(playbackRate: 1.0);


/* RESTORE position*/
if (_audioPosition?.getValue() != null) {
final _res = jsonDecode(_audioPosition.getValue());
int pos = _audioPosition.getValue() == '{}' ? 0 : _res['audioPosition'];
_audioPlayer.seek(Duration(milliseconds: pos));
}

return result;
}

Future<int> _pause() async {
final result = await _audioPlayer.pause();
if (result == 1) setState(() => _playerState = PlayerState.paused);
return result;
}

Future<int> _stop() async {
final result = await _audioPlayer.stop();
if (result == 1) {
setState(() {
_playerState = PlayerState.stopped;
_position = Duration();
});
}
return result;
}

void _onComplete() {
setState(() => _playerState = PlayerState.stopped);
}
}

最佳答案

在 PreferenceBuilder widget 中,您应该删除第一个“Save Position”代码,当 widget 第一次构建时,脚手架返回之前的那两行代码用零值覆盖保存的音频位置的值,这是因为第一次构建小部件时,持续时间为 null。在 sharedpreference 中保存音频位置的更好位置是在

_audioplayer.onAudioPositionChanged()功能在

_initAudioPlayer()

函数。您可以查看下面的代码片段以了解我在说什么

     AudioInformation _audio = AudioInformation('${widget.productName}', p?.inMilliseconds?.round() ?? 0);
_audioPosition.setValue(_audio.toJson().toString());
setState(() {
_position = p;
});
});

这应该可以解决您面临的问题

关于Flutter 保存并恢复 AudioPlayer 位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65145783/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com