Closed westnordost closed 2 years ago
So far, it seems to only occur for the StyleableOverlayManager
and not for its "brother" the QuestPinManager
even though the code is very similar. But this could be just because it is called earlier (it is called right after the map data has been updated, while the quests are only updated after the quests for the updated map data has been updated). So, the bug may not be in StyleableOverlayManager
alone.
I cannot reproduce this crash. But maybe it is related to the mapDataListener
in the StyleableOverlayManager
only being removed when the overlay is either hidden or onDestroy
is called. As explained in the Android documentation, there is no guarantee that onDestroy
is called when the app moves to the background. If it is not called, the mapDataListener
leaks and then causes the crash when onReplacedForBBox
is executed after the next download. At least that's what I could imagine.
My intuition in the previous comment was probably correct. If I comment out the code in the onDestroy
method in the StyleableOverlayManager
and turn on "Don't keep activities" in the Android developer options, I can reproduce the crash after the app is brought back from the background and then manually search for quests.
But this is about onDestroyView
, not onDestroy
, isn't it?
The StyleableOverlayManager
is added to the MainFragment
s view lifecycle in
As far as I understand lifecycles in Android, both onDestroy
and onDestroyView
in a Fragment
are linked to the onDestroy
method of the containing Activity
. But I'm not 100% sure about that.
Hm wow, that would make onDestroyView
and onDestroy
pretty useless. And this would also mean that there are many more places where leaks happen because of this. Some classes have a coroutine viewLifecycleScope which is cancelled on onDestroy
.
Regarding
My intuition in the previous comment was probably correct. If I comment out the code in the onDestroy method in the StyleableOverlayManager and turn on "Don't keep activities" in the Android developer options, I can reproduce the crash after the app is brought back from the background and then manually search for quests.
What code did you comment out? Why would you need to comment out code to reproduce the crash?
Yes, that's why listeners are usually removed in onStop
. Alternatively, the View
can observe the changes in the ViewModel
or Controller
, instead of the latter "pushing" the updates to the former, which can result in the type of crash we see here.
To reproduce the crash, I commented out both code lines in onDestroy
in the StyleableOverlayManager
to simulate it not being called. I did this because I do not know the exact conditions when Android omits a call to onDestroy
and enabling "Don't keep activities" ensures that this method is always called when the app goes to the background (at least on my phone). Otherwise, you probably have to hope that Android kills the app in the background after some time or when too many other apps are opened.
Alternatively, the View can observe the changes in the [...] Controller, instead of the latter "pushing" the updates to the former
Why, isn't that the same thing?
No, it is not the same thing. The crash most likely happened because there is a mismatch between the lifecycle state of the Tangram map and the StyleableOverlayManager
. Due to the way the current implementation works, the StyleableOverlayManager
has to keep track of the lifecycle state of the View
s in the MainMapFragment
. If the map is already destroyed and the StyleableOverlayManager
"pushes" a new camera position to the map controller, we get a crash.
However, if we were to use LiveData
or a Kotlin flow
to transmit new camera positions to the map instead, the map could observe this data holder / stream using its own lifecycle. So if the map is no longer there, there is no observer and no crash.
I frequently get reported this crash report now.
I am not completely sure how to reproduce it, but it is relatively recent and it seems to only happen when an overlay is active but the user left the app for a while, then returned to it, then downloaded something.
My first suspicion would be that this
StyleableOverlayManager
is still lingering from before the app was sent to background and while its parentMainFragment
had been destroyed and recreated already, along with the tangramMapController
, it is still around because it still listens to theMapDataWithEditsSource
. I.e. for some reason, it does not unsubscribe on updates fromMapDataWithEditsSource
when its parentMainFragment
s view is destroyed.Since it is relatively recent that this occurs, (can't say exactly when - at least 47.1), could this have something to do with
updateJob
, @Helium314 ? Though, I don't see anything wrong with the code... maybe I am missing something...If anybody can find an exact reproduction, it would be appreciated too. Since this issue seems to be happening so often, I would really like to get this fixed before releasing v48.0 (which I planned to release today 🤷 ).