I've a problem with a Fragment that embeds the SuportMapFragment from the new Google Maps API. When my fragment is created it fetches some data in an AsyncTask
beginning in the onResume
method. While this happens the MapFragment remains off-screen, instead a progress bar is displayed.
When the AsyncTask
is completed, I register with the onGlobalLayout
event of the mapView. Then I display the fragment, which results in the map view being shown and layouted. onGlobalLayout
is triggered and the animation starts.
This worked fine for quite some time, until I started optimizing the operations in the data gathering AsyncTask
to complete almost instantaneously. Now the app will often crash when started, more often in Release than Debug, which is why I think that I'm dealing with a racing condition here that I'm not aware of.
The exception reads:
Map size should not be 0. Most likely, layout has not yet occured for the map view.
Any insights are greatly appreciated.
For reference: This is the code that seems to cause the crash:
// Hide status UI
this.progressBar.setVisibility(View.INVISIBLE);
this.statusTextView.setVisibility(View.INVISIBLE);
// Update state
this.uraDataDownloadFinished = true;
// Schedule map translation to occur when layout is complete
final View mapView = this.mapFragment.getView();
if (mapView.getViewTreeObserver().isAlive())
{
mapView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
@SuppressWarnings("deprecation")
@SuppressLint("NewApi") // We check which build version we are using.
@Override
public void onGlobalLayout()
{
Log.d(TAG, "onGlobalLayout()");
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
{
mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
else
{
mapView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
// here we crash
this.map.animateCamera(
CameraUpdateFactory.newLatLngBounds(
LatLngBounds.builder()
.include(topLeft)
.include(topRight)
.include(bottomLeft)
.include(bottomRight)
.build(),
0),
durationMs,
null);
}
});
}
// Show map (which will eventually trigger onGlobalLayout)
this.getFragmentManager().beginTransaction().show(this.mapFragment).commit();
this.mapFragment.getMap().setOnCameraChangeListener(this);
Thanks a lot!
I am not sure but as you are using AsyncTask is probably that you are trying to get map bounds before map has undergone layout.
You can see the documentation, it suggest to use newLatLngBounds(boundary, width, height, padding)
instead .
Try this one, it works for me:
map.setOnCameraChangeListener(new OnCameraChangeListener() {
@Override
public void onCameraChange(CameraPosition arg0) {
// Move camera.
map.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 10));
// Remove listener to prevent position reset on camera move.
map.setOnCameraChangeListener(null);
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With