audioplayers icon indicating copy to clipboard operation
audioplayers copied to clipboard

Player has not yet been created or has already been disposed. at a8.m.q() at a8.m.J() at a8.m.n()

Open ehtiqamar opened this issue 1 year ago • 8 comments

Checklist

  • [X] I read the troubleshooting guide before raising this issue
  • [X] I made sure that the issue I am raising doesn't already exist

Current bug behaviour

In release mode, the audioplayer causes random crashes on exiting and re-entering a screen where audioplayer plays a background song. I'm releasing the resources with await and disposing the audio player and when I play a song I do check if the player is already disposed then create a new instance and release any other resources.

Expected behaviour

It should play normally without crash

Steps to reproduce

  1. Enter the screen with audioplayer
  2. Exit the screen
  3. Re-enter

Code sample

 Future<void> play(String fileName, {bool loop = false}) async {
    if (_audioPlayer.state == PlayerState.disposed) {
      _audioPlayer = AudioPlayer();
    }
    await _audioPlayer.release();
    _audioPlayer.play(AssetSource('sounds/$fileName'), volume: _volume);
    if (loop) {
      _audioPlayer.setReleaseMode(ReleaseMode.loop);
    }
  }

Affected platforms

Android

Platform details

Platform 1: Android Moto C Plus Platform 2 : Android 13 Redmi 11 Prime

AudioPlayers Version

4.1.0

Build mode

release

Audio Files/URLs/Sources

https://pixabay.com/sound-effects/click-button-140881/

Screenshots

No response

Logs

Fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: PlatformException(Unexpected AndroidAudioError, Player has not yet been created or has already been disposed., java.lang.IllegalStateException: Player has not yet been created or has already been disposed.
	at a8.m.q()
	at a8.m.J()
	at a8.m.n()
	at a8.m$b.d()
	at a8.m$b.invoke()
	at a8.m$d.invokeSuspend()
	at kotlin.coroutines.jvm.internal.a.resumeWith()
	at q7.d1.run()
	at kotlinx.coroutines.internal.n.run()
	at kotlinx.coroutines.scheduling.k.run()
	at kotlinx.coroutines.scheduling.a.Q()
	at kotlinx.coroutines.scheduling.a$c.d()
	at kotlinx.coroutines.scheduling.a$c.n()
	at kotlinx.coroutines.scheduling.a$c.run()
, null)
       at StandardMethodCodec.decodeEnvelope(message_codecs.dart:652)
       at MethodChannel._invokeMethod(platform_channel.dart:310)
       at AudioPlayer.stop(audioplayer.dart:213)
       at AudioPlayer.release(audioplayer.dart:229)
       at AudioPlayer.dispose(audioplayer.dart:382)
       at AudioManager._disposeMusic(audio_manager.dart:112)
       at AudioManager.dispose(audio_manager.dart:99)

Related issues / more information

No response

Working on PR

no way

ehtiqamar avatar Oct 16 '23 10:10 ehtiqamar

Did you also experience that behavior with the latest version 5.2.0?

Gustl22 avatar Oct 16 '23 10:10 Gustl22

yes

ehtiqamar avatar Oct 20 '23 09:10 ehtiqamar

Sorry, feel free to contribute. We are on our limits right now.

Gustl22 avatar Oct 26 '23 15:10 Gustl22

ListView.builder does not keep state when reordering the child, you will either need to use ListView or ListView.custom and provides your own builder and with this callback

ahsanrazapk avatar Oct 30 '23 00:10 ahsanrazapk

ListView.builder does not keep state when reordering the child, you will either need to use ListView or ListView.custom and provides your own builder and with this callback

I don't think that's related to the problem. Anyways, this issue increased by a whole lot after I updated audioplayers to 5.2.1 on the prod build. I'm using audioplayer to play a background music on one of my screens and then dispose it once the screen is closed.

ehtiqamar avatar Dec 07 '23 07:12 ehtiqamar

then dispose it once the screen is closed.

You may have some async calls to the player, which are executed after the Widget's dispose method has been called. This can be avoided by checking if the widget is still mounted, before calling any async player action.

if (mounted) {
   //Do something
};

Gustl22 avatar Dec 07 '23 08:12 Gustl22

@ehtiqamar in your code example you are checking the _audioPlayer, which means that is has to be initialized before. How do you do that?

if (_audioPlayer.state == PlayerState.disposed) {
      _audioPlayer = AudioPlayer();
}

Or can you provide an app example where we can test the back and forth?

Also try to call await for every async operation, if possible (like _audioPlayer.play())

Gustl22 avatar Feb 08 '24 13:02 Gustl22