Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to control audio service from multiple consecutive pages #227

Closed
shimorojune opened this issue Mar 31, 2020 · 4 comments
Closed

Unable to control audio service from multiple consecutive pages #227

shimorojune opened this issue Mar 31, 2020 · 4 comments
Assignees

Comments

@shimorojune
Copy link

Bug Description

My application is a media player and that requires me to be able to control the audio service from multiple consecutive pages.

However, there are two kinds of errors based on the type of page navigation used:

Push/PushNamed navigation
When a new page with audio_service controls is pushed over another page with audio_service controls, the audio_service is controllable from the pushed page, but once the pushed page is popped, the initial page is not able to control the service properly. (all audio_service controls will be pending till a hot restart)

PushReplacement/PushReplacementNamed navigation
When a new page with audio_service controls is pushed with replacement over another page with audio_service controls, the following error is raised:

E/flutter (15991): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: PlatformException(error, Attempt to invoke virtual method 'android.support.v4.media.session.MediaControllerCompat$TransportControls android.support.v4.media.session.MediaControllerCompat.getTransportControls()' on a null object reference, null)
E/flutter (15991): #0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:569:7)
E/flutter (15991): #1      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:321:33)
E/flutter (15991): <asynchronous suspension>
E/flutter (15991): #2      AudioService.pause (package:audio_service/audio_service.dart:627:20)
E/flutter (15991): #3      _CalendarPage2State.build.<anonymous closure> (package:audioservice/pages/calendarPage2.dart:88:32)
E/flutter (15991): #4      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:706:14)
E/flutter (15991): #5      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:789:36)
E/flutter (15991): #6      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
E/flutter (15991): #7      TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:486:11)
E/flutter (15991): #8      BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:264:5)
E/flutter (15991): #9      BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:199:7)
E/flutter (15991): #10     PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:467:9)
E/flutter (15991): #11     PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:76:12)
E/flutter (15991): #12     PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:117:9)
E/flutter (15991): #13     _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:379:8)
E/flutter (15991): #14     PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:115:18)
E/flutter (15991): #15     PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:7)
E/flutter (15991): #16     GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:218:19)
E/flutter (15991): #17     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:198:22)
E/flutter (15991): #18     GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
E/flutter (15991): #19     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)
E/flutter (15991): #20     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)
E/flutter (15991): #21     _rootRunUnary (dart:async/zone.dart:1138:13)
E/flutter (15991): #22     _CustomZone.runUnary (dart:async/zone.dart:1031:19)
E/flutter (15991): #23     _CustomZone.runUnaryGuarded (dart:async/zone.dart:933:7)
E/flutter (15991): #24     _invoke1 (dart:ui/hooks.dart:273:10)
E/flutter (15991): #25     _dispatchPointerDataPacket (dart:ui/hooks.dart:182:5)
E/flutter (15991):

Disclaimer
I have implemented WidgetsBindingObserver and WillPopScope as done in your example in both pages.

Minimal reproduction project
I have modified the example application to better showcase this bug. Please clone my fork and run the example app.
https://github.com/RohitRajP/audio_service.git

To Reproduce
Steps to reproduce the behavior:

  1. Start audio_service
  2. Push or Push Replacement to another page containing audio_service connection.
  3. The controls linked to the audio_service in the app will become non responsive or raise the errors shown.

Expected behavior
The audio_service must be controllable from any page in the same application.

Runtime Environment (please complete the following information if relevant):

  • Device: Android Emulator / Samsung Galaxy S9+
  • Android version: 10.0

Flutter SDK version

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, v1.12.13+hotfix.8, on Microsoft Windows [Version 10.0.18362.720], locale
    en-IN)

[√] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[√] Android Studio (version 3.5)
[√] VS Code (version 1.43.2)
[√] Connected device (1 available)

*** Additional Information***
This bug is not present, when we navigate to a page that does not contain audio_service connection before navigating to the destination page containing the audio_service controls.

@ryanheise
Copy link
Owner

Hi @Rohitrajp

The problem appears to be that you are pushing the second page onto the stack, while the home page isn't completely removed from the stack, and isn't disposed. So you haven't disconnected from the home page before connecting in the second page.

There are two ways to approach this. One way which is described in the wiki tutorial is to push the connection logic up to a higher point in the widget tree that is shared across all screens. An alternative would be to make each screen implement RouteAware so that you can detect when another screen is pushed on top of the current one and disconnect then before the next screen has a chance to connect.

@shimorojune
Copy link
Author

Hi @ryanheise

First of all, apologies for this huge delay in response.

Thank you for the above mentioned alternatives. I have tried out both RouteAware as well as moving the connection logic to the top of widget hierarchy, and I have found the latter to work better than the former since it provides a better sense of stability, and routeAware was not always very predictable and required a lot of extra code and maintenance.
So, I have implemented the connection logic in the main.dart file and passed callback methods to the children.

Thank you for taking your time to advise on this issue I was facing, it's a real life saver.
If there are no more pointers to add from your side, please close this issue as it has been resolved.

@ryanheise ryanheise self-assigned this Apr 10, 2020
@ryanheise
Copy link
Owner

Great. I've now officially added the AudioServiceWidget into git and this will be the recommended approach from the next release.

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs, or use StackOverflow if you need help with audio_service.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 21, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants