-
-
Notifications
You must be signed in to change notification settings - Fork 82
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
Memory Leak on Android #12
Comments
I will take a look soon. In order to maintain unification between iOS and Android, my feeling is that reference counting can be done without having to track multiple requests. |
Not sure what you mean exactly. :-) |
I was thinking of implementing an approach on the Android side that corresponds to how broadcast streams work in Dart. Broadcast streams do a sort of reference counting so that But anyway, now that I've had a chance to investigate your issue, I don't think we need to go with the above plan (at least for now). First, I noticed that the But even if that fails, it is intended that the plugin should automatically unregister the noisy receiver when the android context is destroyed if it hasn't been unregistered already. There is code to handle this already which should "normally" work, because when the activity is destroyed, I would expect the FlutterEngine to detach from the plugin and there is code in the plugin that then kicks in and it unregisteres the noisy receiver at this point. The fact that this is not happening in your app suggests that your FlutterEngine is not being destroyed when the activity is destroyed. Are you able to share any information about the way you're using FlutterEngines in your app? Are you using any other plugins that do anything special with FlutterEngines? |
This is exactly what should happen! The engine we are running is just regular (Flutter 1.20.4) and besides the fact that we run multiple isolates it should not matter. There's this: @Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
androidAudioManager.dispose();
instances.remove(this);
} Maybe add a The message handling (invokeMethod) currently also requires this line:
Which really should be removed as it could burn. Letting the native side implement a EventChannel is much easier for this case. Also, public AndroidAudioManager(Context applicationContext, BinaryMessenger messenger) {
this.applicationContext = applicationContext;
this.messenger = messenger;
channel = new MethodChannel(messenger, "com.ryanheise.android_audio_manager");
channel.setMethodCallHandler(this);
audioManager = (AudioManager)applicationContext.getSystemService(Context.AUDIO_SERVICE);
instances.add(this);
registerNoisyReceiver();
} Whenever AndroidAudioManager is instantiated, it registers a broadcast receiver; but our App does not need to read this information at that point in time. |
Oh, yes you're right that it registers the broadcast receiver in the constructor. That's certainly a mistake. I've just committed changes to fix the broadcast receiver registration and unregistration as well as set the channel to However, I'd be interested to understand why your FlutterEngine isn't triggering the You mentioned that you're using multiple isolates, but are any of those isolates backed by FlutterEngines? Are you using any plugins that create FlutterEngine instances such as flutter_isolate, android_alarm_manager, audio_service, etc? Are you able to possibly provide a minimal reproduction project? |
I've just noticed some more things I can set to null, so I'll push a new commit in a moment. |
The latest commit now does a bit more null setting. |
Hi @ened is the latest commit working for you? |
Will test today, sorry for the delay. |
@ryanheise unfortunately the GIT version requires rxdart 0.25.0 now, while our App is still pinned to 0.24.0.. so will need a bit more time to evaluate |
Sorry about that, I have just updated the dependency to ">= 0.24.1 < 0.26.0" which I believe should allow your app to resolve the dependency. |
Any updates on your end? I suspect the above issue should be fixed. Although audio_session was designed with multiple FlutterEngine instances in mind, the broadcast receiver itself probably should be a singleton registered with the application context, and using that reference counting approach I alluded to earlier (we don't really want multiple instances of the noisy broadcast receiver in the same app). But that being said, this should not affect you unless you are actually requesting audio focus simultaneously from different FlutterEngine instances (and there would probably be preferable ways to design the app architecture in that case). So that is probably a low priority improvement. At the very least, I would expect with the latest release that the memory leak is resolved, although I don't have your test case to confirm. Once you confirm, I can push out the next release, and roll these changes into the nnbd branch. |
Speaking of the multiple FlutterEngine instances issue, I noticed you are working on a PR for cloud_firestore's issue of the same variety. I'm not sure if you are aware of it, but there was a similar issue reported before yours here: firebase/flutterfire#3671 . And here was my suggested solution to whoever wanted to implement it. I have no need for cloud_firestore personally, but users have reported that your PR didn't fix that issue (see firebase/flutterfire#3671 (comment)). I thought you might like to take a look at it and see if there is any way you might be able to modify your solution in a way that solves both problems in a more general way. |
The above changes are now published in release 0.0.10. |
@ryanheise thank you for releasing 0.0.10. I have integrated it and can confirm the leak is gone. I will look into the issues mentioned above (thank you) regarding the cloud_firestore PR. |
Used version audio_session 0.0.9.
Instead of registering the receiver any time a plugin is instantiated, the native side of the plugin should expose a single event channel per use case and the dart side exposes the broadcast stream to the application.
The native side should only register the receive when it itself has stream subscriptions and cancel them when they cancel.
@ryanheise do you have time to work on this any time soon?
The text was updated successfully, but these errors were encountered: