Status Update
Comments
da...@michelin.com <da...@michelin.com> #2
at android.graphics.Canvas.<init>(Canvas.java:113)
at com.google.maps.api.android.lib6.impl.a.a(:com.google.android.gms.policy_maps_core_dynamite@231710105@231710102065.533527097.533527097:1)
at com.google.maps.api.android.lib6.phoenix.be.run(:com.google.android.gms.policy_maps_core_dynamite@231710105@231710102065.533527097.533527097:2)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8757)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
AND
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.isMutable()' on a null object reference
at android.graphics.Canvas.<init>(Canvas.java:113)
at com.google.maps.api.android.lib6.impl.a.a(:com.google.android.gms.policy_maps_core_dynamite@231112107@231112103065.517507265.517507265:1)
at com.google.maps.api.android.lib6.phoenix.be.run(:com.google.android.gms.policy_maps_core_dynamite@231112107@231112103065.517507265.517507265:2)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7884)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
iv...@google.com <iv...@google.com> #3
Thank you for posting.
We'll need some more details to troubleshoot this issue - please provide the following, in particular steps to reproduce the issue:
-
Put together a simplified reproduction case (
http://sscce.org/ ) and add it to a git hosting provider (e.g. github, bitbucket, etc)? The easiest way to do this might be to fork the Google Maps Android API Samples Repository and modify one of the existing demo activities:https://github.com/googlemaps/android-samples -
List steps to reproduce the problem
- Maps SDK client library version (used to build your app):
- Maps renderer (Latest or Legacy):
- Devices you have verified this issue on:
- Google Play Services version on the device:
- Android version:
- Manufacturer and model:
- Was this working correctly on a previous version of Google Play Services? (If yes, which client library and SDK version?)
- Attach the following:
- screenshots
- sample code
- an APK if possible.
- If the problem exhibits itself in a released version of your app on the Play Store, optionally link us to the app, and explain how to reproduce the issue in your app.
da...@michelin.com <da...@michelin.com> #4
Maps SDK client library version - 18.1.0
Maps renderer- MapsInitializer.Renderer.LATEST
Google Play Services version on the device: NA
Android version: Android 13, Android 12, Android 11
Manufacturer and model: samsung Galaxy S22 Ultra, samsung Galaxy S23 Ultra, Galaxy Z Fold4, Google Pixel 7 pro, Pixel 6 Pro, Pixel 6
Was this working correctly on a previous version of Google Play Services? (If yes, which client library and SDK version?) : Yes,
This issue arising when I integrated, -
MapsInitializer.initialize(applicationContext, MapsInitializer.Renderer.LATEST, this)
and taken callback in -
override fun onMapsSdkInitialized(renderer: MapsInitializer.Renderer) {
when (renderer) {
MapsInitializer.Renderer.LATEST -> Timber.d("MichelinGuideApplication = %s", "The latest version of the renderer is used.")
MapsInitializer.Renderer.LEGACY -> Timber.d("MichelinGuideApplication = %s", "The legacy version of the renderer is used.")
}
}
It is happening while taking snapshot from map.
App Name:
mi...@gmail.com <mi...@gmail.com> #5
dc...@gmail.com <dc...@gmail.com> #6
bo...@geo-tracker.org <bo...@geo-tracker.org> #7
can't determine specific steps to reproduce, but I see quite some of those crashes in Firebase.
iv...@google.com <iv...@google.com> #8
Thank you for the updates in this issue.
We have escalated this issue to our specialist for further evaluation. Rest assured that we'll get back for the updates.
as...@google.com <as...@google.com> #9
Thank you for the report.
Based on the stack traces, we can confirm one scenario that reproduces the crash: an app calls GoogleMap#snapshot
The Legacy renderer doesn't crash in this scenario. However, we notice that it does not produce a snapshot if the method is called while the app is in the background, and produces one as soon as the app comes to the foreground.
We are investigating the best way to resolve this issue in the Latest renderer. In the mean time, one possible workaround is to modify your app to detect if it is in the foreground before taking a snapshot, for example by calling ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)
bo...@geo-tracker.org <bo...@geo-tracker.org> #10
However, I tried it out and unfortunately, the crash immediately popped up again on a newer version of the app - while building the pre-launch report in Google Play.
Could it be because the snapshot gathering is started while the app is in the foreground, but then the app is minimized along the way?
as...@google.com <as...@google.com> #11
#10: I think that is possible, although so far I find the snapshot process does not take that long.
We see an app that regularly (e.g. every X seconds) takes a snapshot. It crashes when it is put on the background. Is your app implementing something like this?
me...@gmail.com <me...@gmail.com> #12
No, we captured the snapshot when the app is foreground only as per implementation. May be minimise the app results put on the background and crashed at the same time while or after captured the snapshot.
bo...@geo-tracker.org <bo...@geo-tracker.org> #13
Also, the fragment with the map can be invisible during the snapshot call (being on another tab). Could that cause an issue?
as...@google.com <as...@google.com> #14
#13:
Also, the fragment with the map can be invisible during the snapshot call (being on another tab). Could that cause an issue?
Quickly looking at our code, I think that is possible. I'll try to reproduce that to confirm.
bo...@geo-tracker.org <bo...@geo-tracker.org> #15
I push the button that makes a snapshot, and then quickly minimize the app to the background - it crashes silently, when I move it to the foreground again - I see it was restarted.
The check for being in the foreground right before requesting a snapshot is there, but it doesn't help, unfortunately.
pr...@google.com <pr...@google.com> #16
sz...@labmatic.com <sz...@labmatic.com> #17
ra...@google.com <ra...@google.com> #18
We greatly appreciate your patience.
We believe this issue is now fixed, hence marking it as such.
Thanks for working with us!
as...@google.com <as...@google.com> #19
To clarify the status of this issue, we have submitted a fix to our codebase, and it will be released in a future version of Google Play services. We will update here once we have an estimate release date.
as...@google.com <as...@google.com> #20
Hello everyone. We would like to provide an update on this.
To recap, this crash happens when GoogleMap#snapshot
is called when a map is not visible. This could happen when an app is in the background, or if a fragment showing a map is in the background (that is, the fragment is not visible) while the host app or activity is in the foreground.
The Latest renderer does not support taking a snapshot while the map is not visible. This is to avoid non-deterministic behavior. The change we comitted to our codebase is to throw an IllegalStateException
instead of NullPointerException
to inform better what happens. This change is estimated to roll out via Google Play services at the beginning of April 2024.
We will update the SDK's documentation regarding this change.
To our developers: Please make sure your app only calls GoogleMap#snapshot
when a map is visible, and handles IllegalStateException
in case it occurs.
For comparison, the Legacy renderer doesn't immediately throw NullPointerException
when a snapshot is taken while the map is not visible. However, we have seen crashes at other places in the SDK that are likely caused by this.
ma...@googlemail.com <ma...@googlemail.com> #21
But we would like to add to the discussion that the trigger for reproduction is slightly different for us: To best of our knowledge we only take snapshots on location updates while map is visible. This usually works fine. The internal crash in question then only occurs in bad network situations, especially when actively switching between wireless and mobile data.
pe...@gmail.com <pe...@gmail.com> #22
as...@google.com <as...@google.com> #23
There was some delay in deploying the change. The deployment is currently in progress and we'll update here when it is complete.
#21: The change is deployed as an update in Google Play services, and not as a new client library version. See
#22: do you have a sample app that reproduces the issue? (the crash happens even though you have added a try-catch block)
pe...@gmail.com <pe...@gmail.com> #24
(Using latest com.google.maps.android:maps-compose:4.4.0)
as...@google.com <as...@google.com> #25
#24: Hmm, that try-catch block looks so simple, I don't know why it wouldn't catch the exception. If I understand correctly, you can reproduce the crash in your app consistently. So I would suggest you to debug your app around the snapshot
call to see what goes wrong.
pc...@gmail.com <pc...@gmail.com> #26
I can confirm that the try-catch function around the map.snapshot
does not really help since it does not catch the IllegalStateException
thrown. I can also note that the error is not a NPE anymore as written in the description of this issue but rather: java.lang.IllegalStateException: Can't take a snapshot while executing in the background
. So the changes in the play services have been gone through I assume (?). I also need to mention that this error is not happening consistently -at least not in our app, but rather with a frequency of 1/50. I am attaching the relevant piece of code.
as...@google.com <as...@google.com> #27
#26: Yes, the change to make the exception java.lang.IllegalStateException
was fully rolled out via Google Play services in the beginning of May.
Trying to narrow down the problem: are there people here experiencing try/catch not catching the exception when not using Maps Compose library and MapEffect
?
al...@tryfi.com <al...@tryfi.com> #28
We do allow our user to preview the 9:16 format since that is the style of our app. How would we be able to generate a square snapshot of this same map without rendering it in view? I understand we could crop the image, but that's not ideal either since it could cut important parts of the map path off.
Currently I render it behind other views, but that appears to be a reason that this exception fires off.
5a...@gmail.com <5a...@gmail.com> #29
sa...@shiftcare.com <sa...@shiftcare.com> #30
wu...@inston.ltd <wu...@inston.ltd> #31
Maps SDK client library version - 18.1.0
Maps renderer- MapsInitializer.Renderer.LEGACY
Android version: Android 14, Android 13, Android 12, Android 11
device model: most sumsung, redmi, motorola, and others
i run initialize in application:
new Thread(new Runnable() {
@Override
public void run() {
try {
MapsInitializer.initialize(application, MapsInitializer.Renderer.LEGACY, BaseApp.this);
} catch (Exception e) {
}
}
});
and this is the code i launch snapshot ,i run snapshotGoogleMap on resume or button click:
public static void snapshotGoogleMap(LocationTrackerLineView view, final GoogleMap.SnapshotReadyCallback snapshotReadyCallback) {
if (view == null) {
return;
}
if (view.getWidth() <= 0 || view.getHeight() <= 0 || view.getVisibility() != View.VISIBLE || !view.isReady() || !view.isShown()) {
if (snapshotReadyCallback != null) {
snapshotReadyCallback.onSnapshotReady(null);
}
return;
}
final GoogleMap.SnapshotReadyCallback callback = new GoogleMap.SnapshotReadyCallback() {
boolean isShare = false;
@Override
public void onSnapshotReady(final Bitmap snapshot) {
if (isShare) {
return;
}
isShare = true;
if (snapshotReadyCallback != null) {
snapshotReadyCallback.onSnapshotReady(snapshot);
}
}
};
if(view.isShown()){
view.snapshot(callback);
}
//just start launch next page after 800ms
view.postDelayed(new Runnable() {
@Override
public void run() {
callback.onSnapshotReady(null);
}
}, 800);
}
so how can we fix the issue?
jr...@gmail.com <jr...@gmail.com> #32
Fatal Exception: java.lang.IllegalStateException: Can't take a snapshot while executing in the background.
at com.google.maps.api.android.lib6.impl.a.a(:com.google.android.gms.policy_maps_core_dynamite@244125205@244125202032.684868338.684868338:20)
at com.google.maps.api.android.lib6.phoenix.dl.run(:com.google.android.gms.policy_maps_core_dynamite@244125205@244125202032.684868338.684868338:9)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7680)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:423)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
sz...@labmatic.com <sz...@labmatic.com> #33
suspend fun getScreenshot(): Result<Bitmap> = runCatching {
require(isReady) { "Map is not ready" }
fragment.viewLifecycleOwner.lifecycle.withResumed { }
requireNotNull(googleMap.awaitSnapshot()) { "awaitSnapshot returned null" }
}
ri...@gmail.com <ri...@gmail.com> #34
🐞When using googleMap.snapshot {} to capture a screenshot of the map, the app crashes if the map tiles are not fully loaded. This occurs especially on slow internet connections or when loading heavy maps.
📌 Steps to Reproduce
- Open a Google Map in an Android app.
- Ensure the map loads but the tiles are still being fetched (e.g., slow internet or high-resolution maps).
- Call googleMap.snapshot {} before the tiles have finished rendering.
- App crashes with the following exception:
🚨 Root Cause
- googleMap.snapshot {} requires the map tiles to be fully rendered before taking a snapshot.
- If tiles are still loading, the snapshot API crashes.
- Google Maps SDK does not provide a method to check if tiles have finished rendering before calling snapshot {}.
🔥 Workaround: Ensure Map Tiles Are Fully Loaded To avoid this crash, we must wait until the map is fully rendered before taking a snapshot.
✅ Fix: Use setOnMapLoadedCallback() This ensures that the snapshot is taken only after the map has finished loading.
fun takeSnapshot() { if (googleMap == null) { Log.e("MapSnapshot", "Cannot take snapshot, map is null.") return }
googleMap?.setOnMapLoadedCallback {
googleMap?.snapshot { snap ->
if (snap != null) {
Log.d("MapSnapshot", "Snapshot taken successfully")
// Process the snapshot
} else {
Log.e("MapSnapshot", "Failed to take snapshot")
}
}
}
}
🎯 Why This Fix Works ✅ Waits for all tiles to load before calling snapshot() ✅ Prevents crashes due to incomplete rendering ✅ Handles slow internet scenarios gracefully
Description
at android.graphics.Canvas.<init>(Canvas.java:113)
at com.google.maps.api.android.lib6.impl.a.a(:com.google.android.gms.policy_maps_core_dynamite@231710105@231710102065.533527097.533527097:1)
at com.google.maps.api.android.lib6.phoenix.be.run(:com.google.android.gms.policy_maps_core_dynamite@231710105@231710102065.533527097.533527097:2)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8757)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)