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" />
Related
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?
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"/>
I want to design a dynamic UI for my application so in screens with more than 500dp width it will show 2 fragment and otherwise it shows a single fragment.
Here is my layout files:
layout/activity_main:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/frag_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
layout-w500dp/main_activity:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="ir.focusmag.focus.PostsFragment"
android:id="#+id/posts_frag_container"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent"
tools:layout="#layout/fragment_posts" />
<fragment android:name="ir.focusmag.focus.PhotosFragment"
android:id="#+id/photos_frag_container"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent"
tools:layout="#layout/fragment_photos" />
</LinearLayout>
in MainActivity.java there is a check to see whether frag_container is present or not and if it's there it will load the PostsFragment into it:
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first fragment
if (findViewById(R.id.frag_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
firstFragment = new PostsFragment();
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragm_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.frag_container, firstFragment).commit();
}
}
And there is a Listener for clicking on a post to replace the fragment with the details fragment.
The important point here is if we're being restored from a previous state it doesn't do anything.
In usual scenarios this method works but if the user stars the application in landscape mode ( screen width > 500dp ) MainActivity checks for frag_container and as it's not there It will do nothing and then the user will rotates the device to portrait mode and as the savedInstanceState is not null anymore nothing will be loaded into frag_container.
If I remove the check for savedInstanceState, whenever the user rotates the device PostsFragment will be loaded and it's not wanted. for example the user is checking the details and rotates the device and it shows the posts instead of the details.
What can I do to stop this kind of behavior?
I'm following Android Developer's tutorial to do this.
Thanks in advance
This approach is a little bit outdated. If you just started playing with Android and want to see how to handle things modern way, watch Developing Android Apps video course from Google by Google. They will show you how to deal with Master/Detail pattern properly. If you would like to jump immediately to the code, start your Android Studio and create new Activity with the wizard and pick Master/Detail form.
Your new activity's onCreate() method would look like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_list);
if (findViewById(R.id.item_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
// In two-pane mode, list items should be given the
// 'activated' state when touched.
((ItemListFragment) getFragmentManager()
.findFragmentById(R.id.item_list))
.setActivateOnItemClick(true);
}
// TODO: If exposing deep links into your app, handle intents here.
}
Comparing to your current approach, this time for single pane mode fragment is added within XML layout so you don't have to bother with unexpected behavior. You will also see there how layout aliases works.
I know it's not a simple answer you may expect buy it may be the last moment for your application to apply this change. I really encourage you to do it.
If this change is not an option for you consider modifying single pane layout and include fragment there instead adding dynamically. Probably, at the moment, your are not benefit from dynamic fragment at all anyway.
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 Activity and i had set activity's content view as "R.layout.main.xml".And i have an another class which contains animation created using openGL. Now i need to use this animation in the background of the Activity.
The code is like this
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_pixie);
mGLView = new ClearGLSurfaceView(this);
setContentView(mGLView);
}
But my app is Crashing ..How can i solve this.
When you call the setContentView() a second time, you replace what had been set the first time, leaving you with only the background. The crash is most likely because you depend on the elements in the main layout, which is removed.
Rather than calling setContentView() twice, you should include the GLSurfaceView in the main layout. Below is an example of how this can be done:
<?xml version="1.0" encoding="UTF-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent>
<your.application.package.ClearGLSurfaceView
android:layout_width="match_parent"
android:layout_width="match_parent"/>
<!--put the rest of your layout here, i.e the contents of the original R.layout.main_pixie-->
</FrameLayout>
Then you can load this layout in your onCreate() as usual (main_pixie_new refers to the above xml, I just gave it that name to keep things as clear as possible):
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_pixie_new);
}