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!