Description
When starting the Google Maps app (using a "get directions" Intent) from within my own app, part or all of the map presented in my app sometimes (~25-50% of the time) turns black during the screen transition. Here are videos from a minimal working example:
Real device
A rectangular piece of the map that is covered by a transparent view turns black during the transition. Note that while the transparent part of the view is unnecessary in this MWE, it is a required part of my actual application.
Emulator
The entire map turns black during the transition.
The Activity shown has the following layout:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.gms.maps.MapView
android:id="#+id/map_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_marginTop="48dp"
android:background="#android:color/white" />
<Button
android:id="#+id/button_action"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>
</RelativeLayout>
and code:
public class MapsActivity extends AppCompatActivity {
private MapView mapView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
findViewById(R.id.button_action).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View view) {
final Intent intent = new Intent(ACTION_VIEW, Uri.parse("google.navigation:q=42.3314,-83.0458"));
intent.setPackage("com.google.android.apps.maps");
startActivity(intent);
}
});
mapView = (MapView) findViewById(R.id.map_view);
mapView.onCreate(savedInstanceState);
}
// All the other overridden lifecycle methods, forwarded to mapView correctly.
}
The project uses the latest version of Google Play Services (10.0.1). Full code is available on GitHub.
I've read through a bunch of legacy issues with maps turning black, but those seem to relate to a single map being scrolled (e.g. https://code.google.com/p/gmaps-api-issues/issues/detail?id=4659).
I don't have a reliable way to reproduce the issue, even within the MWE, but it happens often enough to be easy to observe and capture.
Device specs seem to make a difference (higher spec devices exhibit the issue less often).
Questions
What's the underlying cause of this issue?
Is there something I should (or should not) be doing to avoid this ugly behavior when launching the Google Maps app?
Related
I have a list view that is populated through a string-array in the xml, not run time and I'm trying to set the background color of specific items in the list using:
listView.getChildAt(x).setBackgroundColor(Color.BLACK);
I need this to happen before it's visible, but it gives an error when I use it in onCreate() or onStart(), but works if I run it on a button press. I've tried searching for an answer but can't seem to find any event that happens late enough for it to work.
getView() would be the best place to do this, but you don't have access with the way you are doing this with android:entries=.... Instead, you can post a runnable to the message queue to change the color after layout occurs like the following:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.layout).post(new Runnable() {
#Override
public void run() {
findViewById(R.id.view).setBackgroundResource(android.R.color.holo_red_dark);
}
});
}
Here I have used a simple View for demonstration but the same technique should work for your ListView.
Here is the XML I used if you want to work with it:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<View
android:id="#+id/view"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#android:color/holo_blue_light" />
</LinearLayout>
Here's a link to post. The runnable kicks off before onStart(). So, if that's a requirement, then this way may not work for you.
Hi everyone I have an Activity which is loading after I click on an Item inside my Listview.
This activity shows the location inside a MapView like this:
<FrameLayout
android:id="#+id/mapContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toEndOf="#+id/imageView"
android:layout_above="#+id/button"
android:layout_below="#+id/imageView"
android:layout_alignParentStart="true"
android:layout_marginTop="10dp" >
<TextView
android:id="#+id/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Loading Map..." />
</FrameLayout>
The Problem is, that I want to show the Map to the User later on if he/she clicks on a button.
But the Activity is loading very slow and even has a black blank screen before showing anything. This looks very unprofessional, and seems wrong.
I tried making the MapView invisible first and show it when user hits the button, but it is loading when the activity starts.
I'am trying following code:
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_event);
mapView = new MapView(SingleEvent.this);
mapView.onCreate(savedInstanceState);
com.google.android.gms.maps.MapView.LayoutParams mapParams = new com.google.android.gms.maps.MapView.LayoutParams(com.google.android.gms.maps.MapView.LayoutParams.MATCH_PARENT,220);
mapContainer = (FrameLayout) findViewById(R.id.mapContainer);
mapContainer.addView(mapView, mapParams);
This one is working it is showing the map, but the activity is loading to long with a black blank screen, until my activity is loaded.
Is there any way to first load the activity and after that load the MapView on a button click?
I'am trying to do something like this:
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mapView = new MapView(SingleEvent.this);
mapView.onCreate(savedInstanceState);
com.google.android.gms.maps.MapView.LayoutParams mapParams = new com.google.android.gms.maps.MapView.LayoutParams(com.google.android.gms.maps.MapView.LayoutParams.MATCH_PARENT,220);
mapContainer = (FrameLayout) findViewById(R.id.mapContainer);
mapContainer.addView(mapView, mapParams);
}
},1000);
But with that code, the Map isnt loading its only showing the grey blank grid.
I think its because of the savedInstanceState but maybe there is a work around?
I tried to save the Bundle savedInstanceState, loading like above.
You can use a MapFragment. In onCreate(), you can set visibility to invisible. When the map is ready, onMapReady() will be called and you can configure map settings there.
I had the same issue which was occurring due to hardware accelartion and largeheap. I had used these features at application level. But I removed them from the app level and used them in the activity they used. The Activity which contained SupportMapFragment didn't need these features. So I moved this code from Application tag to Activity in Manifest.
Issue was in Manifest.
<application
android:label="#string/app_name"
android:theme="#style/AppTheme"
android:hardwareAccelerated="false"
android:largeHeap="true">
Remove from Manifest and Use in the Activity
<activity
android:name="com.mycompayname.activities.SignUpActivity"
android:hardwareAccelerated="false"
android:largeHeap="true"/>
Is there a way to implement mapview version 1 inside fragment?
I tried sth like:
MainActivity:
public class MainActivity extends FragmentActivity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
Then, I want 2 fragments . One that has the mapview and second which will have a textview in which the location will be shown.
I can't implement the first fragment.I can't figure how to implement the map.I mean , for the mapview to work it needs "extends MapActivity" but I need "extends fragment".
Also , in main.xml how to do it?I tried :
<fragment
class="com.google.android.maps.MapView"
android:name="com.example.....MapClass" //is this right?but it is necessary for fragment?
android:id="#+id/fragment1"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent"
android:apiKey="mykey" />
<fragment
class="com.example...getloclass"
android:id="#+id/fragment2"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
From here https://developers.google.com/maps/documentation/android/v1/hello-mapview, you can see that
Version 1 of the Google Maps Android API as been officially deprecated
as of December 3rd, 2012
So you shouldn't use MapView anymore. I suggest you use a MapFragment instead. See the excellent documentation for it here: https://developers.google.com/maps/documentation/android/reference/com/google/android/gms/maps/MapFragment
Im having some trouble accessing Hello Mapview at the moment, http://developer.android.com/training/tutorials/views/hello-mapview.html, but i think ive done this correctly. I want to show a map in a separate activity.
Map.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.google.android.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:apiKey="working key"
/>
</LinearLayout>
Button onclick event that should show my map
public void showMap(View v){
Intent intent = new Intent(getBaseContext(), GoogleMapsActivity.class);
startActivity(intent);
}
GoogleMapsActivity.java
public class GoogleMapsActivity extends MapActivity
{
MapView mapView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map);
mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
}
The activity is added to my manifest, Google apis is included etc. Its working if i put the map in my main activity, but not in my GoogleMapsActivity. Please tell me what ive missed here.
Thanks
From https://developers.google.com/maps/documentation/android/reference/:
Only one MapActivity is supported per process. Multiple MapActivities running simultaneously are likely to interfere in unexpected and undesired ways.
Basically, you can only have 1 MapActivity, and MapViews can only be hosted in a MapActivity. What you want basically isn't possible.
EDIT: not sure it would work for you, but you might try marking your second activity with android:process=":remote" and see if that works, but I doubt it.
EDIT: there is evidently some confusion. Look at https://developers.google.com/maps/documentation/android/reference/com/google/android/maps/MapView. This states that:
A MapView can only be constructed (or inflated) by a MapActivity. This is because it depends on threads which access the network and filesystem in the background; these threads must be shepherded by the lifecycle management in MapActivity. Tiles are cached on the filesystem in your application's directory. The cache is auto-managed so you don't need to do anything with it, and can delete it at any time.
I'll re-iterate: You CAN'T display a MapView in any other activity.
The problem was a misspelling in my manifest file,
<activity android:name=".GoogleMapActivity" /> //missing an "s"
I have an app which contains an activity which is a MapviewActivity and is mostly a mapview.
However I have noticed that the start up time of the activity is really slow and causes a lag from the moment the button is pressed to go in to the map activity. I feel this creates a bad user experience and would like to avoid this.
I have already set the background of the map activity to #null as suggested by one of the UI improvement articles on googles developer page, which I feel does not do the trick.
Is there a way to improve this? I would not like the main home screen to get stuck on the launch of the activity, even a transfer to the map activity and then loading the mapview would be better.
Thanks,
Jason
You could try removing the MapView from your layout. Then, in onCreate(), use post() to schedule a Runnable to add in the MapView and do your map-related initialization from Java. By using post() (or, potentially, postDelayed()) to postpone the MapView further, you should be able to render the rest of the activity first.
I haven't tried this, so YMMV. :-)
This has been bugging me for a while and I worked this out by expanding on on CommonsWare's answer:
I am currently using this solution that sped up my Activity loading time greatly and make everything look as smooth as it gets.
My MapActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map); // See activity_map.xml below.
// Start a runnable that does the entire Map setup.
// A delay does not seem to be necessary.
Handler mapSetupHandler = new Handler();
Runnable mapSetupRunnable = new Runnable() {
public void run() {
FragmentManager fragMan = getSupportFragmentManager();
FragmentTransaction fragTransaction = fragMan.beginTransaction();
final SupportMapFragment mapFragment = new SupportMapFragment();
fragTransaction.add(R.id.container_map, mapFragment, "mapFragment");
fragTransaction.commit();
// At the end, retrieve the GoogleMap object and the View for further setup,
// zoom in on a region, add markers etc.
mapFragment.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMapView = mapFragment.getView();
setUpMap();
}
});
}
};
mapSetupHandler.post(mapSetupRunnable);
}
layout/activity_map.xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--This FrameLayout will be used by the GoogleMap-->
<!--as a container for the SupportMapFragment.-->
<FrameLayout
android:id="#+id/container_map"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_above="#id/bar_room_password"
android:layout_below="#id/toolbar">
<!--Initially the container is filled with a placeholder image.-->
<!--A small, heavily blurred image of a map screenshot is used-->
<!--in order to fake a loading map.-->
<ImageView
android:id="#+id/image_map_placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="50"
android:contentDescription="#string/map"
android:scaleType="centerCrop"
android:src="#drawable/placeholder_map" />
</FrameLayout>
[... more, unrelated Views...]
</RelativeLayout>
The Activity appears quickly because the setup is handled inside of a Runnable. Also, instead of just showing an empty View while the GoogleMap is doing its setup and downloads, I show a vague fake image of a map.
The Google logo is being placed on top of the ImageView relatively early so it looks pretty convincing with just a 128x128 pixel image:
I tried CommonsWare's answer, but there was a significantly delay launching even a bare MapActivity without a MapView in it.
So, I put another activity in the middle, "MapLoading". My home activity launches MapLoading, which then uses post() to immediately launch the MapActivity. Because of the lag, the app sticks on MapLoading for a few seconds (which is the intended result, as opposed to sticking on my home activity).
The MapLoading activity has noHistory set so when the back button is clicked from the MapActivity it goes right through to the home screen. Future launches of the MapActivity are very fast and the MapLoading activity just flashes on the screen.
Here is the code for MapLoading (the activity with the MapView in it is called Map):
public class MapLoading extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.maploading);
new Handler().post(new Runnable() {
public void run()
{
startActivity(new Intent(MapLoading.this, Map.class));
}
});
}
}
Here is its layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/maploading"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:textSize="14pt"
android:text="Loading map..."
/>
</RelativeLayout>
And the corresponding stanza in AndroidManifest.xml:
<activity android:label="#string/app_name"
android:name="MapLoading"
android:noHistory="true" />