I have a MapActivity where you can switch between MapView (Google Maps) and OfflineMapView (my class, shows a map previously downloaded to SD card). When switching between maps I want to completely destroy and create the map views so that only one map view is in the memory. I want this for 2 reasons:
My OfflineMapView takes most of available memory for caching tiles.
Google MapView has some attached threads which I don't want running when OfflineMapView is visible.
I tried to remove the MapView from layout and null my reference to it but when I want to show it again I get an exception saying that MapActivity can have only one MapView.
EDIT:
The presence of Google MapView (visibility is set to GONE) doesn't have any effect on OfflineMapView FPS. I didn't get any OutOfMemoryErrors either.
Use ActivityGroup as your Activity class and have it start and stop sub-activities for each type of map. For example, to get the view for the Google Map:
Intent intent = new Intent(this, GoogleMapActivity.class);
Window window = getLocalActivityManager().startActivity("google-map", intent);
View googleMapView = window.getDecorView();
container.addView(googleMapView);
to destroy it:
container.removeView(googleMapView);
getLocalActivityManager().removeAllActivities();
and do the same with your offline map. This should completely stop the MapActivity and it's threads.
Note that I have found LocalActivityManager.destroyActivity() to be buggy, so I used LocalActivityManager().removeAllActivities() in the example since it does work for this case.
Related
I have recently started using here maps api, and i have encountered some difficulties implementing maps. When app goes in background and i come back to app, map view screen is black. I should mention that i'm using MapView and not MapFragment. MapView is inside fragment view. Beside that map is showing clearly.
mapView.setMap(mMap);
mMap = mapView.getMap();
mMap.setZoomLevel(16);
mapMarker = new MapMarker();
mapMarker.setTitle("Neki naslov");
mapMarker.setDescription("Neki opis");
mapMarker.setDraggable(true);
mapView.setMapMarkerDragListener(mOnDragListener);
mapMarker.setCoordinate(PositioningManager.getInstance().getLastKnownPosition().getCoordinate());
mMap.addMapObject(mapMarker);
mapMarker.showInfoBubble();
mMap.setCenter(PositioningManager.getInstance().getLastKnownPosition().getCoordinate(),
Map.Animation.NONE);
Most likely, you did not call MapView#onResume() and MapView#onPause() as part of the activity / fragment life cycle. If it is not called, the underlying rendering thread will not be resumed.
#Dusan, your code does not have an image for the marker, so there is no marker to show.
I have an application in which I am attaching different fragment with activity. and in that activity container I am replacing different fragment.
So at the start of the activity I replace the MapFragment in the activity container. Later on I replace other fragment and then from main activity I replace again the map fragment. Although I think I have wrong implementation of map in fragment but I wanted to know and wanted to do some different things and I think as I have no better understanding of fragment so I think that is why I am getting null pointer exception
What I have done SO far
Case 1.
AS I said On App start I am replacing map fragment but doing nothing more except showing user current location by just setting user location enable in google map v2. so on the button click of the map let say show other location , fetch location information from server and draw pins on the map. this is working good as far as the map fragment is there.
Case2
if user click button let say "Show location" while there is other fragment in the container let say About Us fragment which contains app info , so now on this button it is supposed that map fragment should be replaced again and then the function in that fragment which is going to download locations from the server and to show them on map should start working as I am calling on button click
fragmentTransaction1.replace(R.id.frame, myMapFragment, "MyMapFragment").commit();
fragmentManager.executePendingTransactions();
myMapFragment.GetAllLocations("friendsLocation");
so this GetLocations() should run , but at this stage the app crash saying null pointer exception. and in this function myMapFragment.GetAllLocations("friendsLocation")
there is a need of context which I taking as getActivity(), the context is needed as I have to make a call to web api using ION library which needs context.
So these are my basic questions
How can I get to know that fragment is started and then the function which I have called from MainActivity should run after the mapFragment is loaded and started so that I can not get the null context in the getActivity() ?
Is there any other way of doing that , I hope you understand my need that is , I want to replace the map fragment and I want to call the fragment method on the same time by passing the parameters to fragment method from the main activity , but How can it be done ?
An idea is in my mind and that is while replacing back the map fragment through Mainactivity button , i should set some static value in the mapFragment let say
public static boolean isLocationShouldDownload== flase //in map
fragment
I should set it true while replacing fragment
and then when the fragment is started after it is in running condition it should check this variable if it is true (set by the main activity) then it should download and start plotting pins. but I have no idea how can I get to know that fragment is running .
I have no idea how and where I have to implement my idea which I have stated in point no 3.
Please share your idea with me and give me suggestion or share me a source code that how can I achieve this task through main activity that fragment should replace and download the locations and to show them on map without getting app crash.
As far as I can see, MapFragment has an issue with transition animations. All views on the layout are getting shown immediately, including the MapFragment's own views (like zoom buttons). But the map itself gets loaded with a lag only after the animation is completed.
In order to illustrate the problem, I did the following:
I changed one of the Activities in the Google maps android API examples slightly. It opens a blank activity via an Action Item. When I click back button, the map gets loaded, but only after the transition is completed.
I exaggerated the transition effect a little bit, so that you can see the problem better. I set the transition animation speed in Developer Options to 5x. Even on 1x speed, this lag is disturbing though.
See this video: http://www.youtube.com/watch?v=12SEotktlXI
Do you have any suggestion to prevent this lag? Why do all views get loaded immediately but the map itself doesn't?
Testing environment: Nexus 5, Android 4.4.2, unrooted
Edit: This problem also occures when MapView is used instead of MapFragment.
Reason: Its because as soon as you settings activity will be shown, the map activity will be on its onpause() state; thus, I assume android management reclaimed the memory from the map activity.
Solution:
Make a static class and declare you map statically there, to avoid android from reclaiming the memory used by your map.
Ex.
//your static class
public class MapData{
public static GoogleMap map;
}
//your map activity
public class MapActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(MapData.map != null)
MapData.map = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
}
}
When I rotate my device, Google Maps v2 refreshes. How do I prevent this refresh from occurring? I'm adding the map dynamically in a tab of a SherlockFragment.
I fixed the problem by adding to the Activity in AndroidManifest.xml:
android:configChanges="orientation|screenSize"
Edit (04/28/2017) :
From the Android Documentation:
Note: Using this attribute should be avoided and used only as a last resort. Please read Handling Runtime Changes for more information about how to properly handle a restart due to a configuration change.
Maybe you could look at this answer, which properly saves the SupportMapFragment using the Bundle available in the onCreate method of FragmentActivity.
Emil's comment is right in explaining why the view of your map is being reset. Forbidding the orientation change via the manifest however is not good style.
You need to retain the map fragment somehow or retain the fragment that contains the map fragment. After your 'host' activity has been recreated, you need to reattach the fragment to the activity instead of creating a new one.
I don't have any code here but you'll find information about retaining fragments on the web.
As an alternative you could save your maps state (foremost the camera position I guess) somewhere else and restore it after the fragment has been recreated.
You can't, the map is getting refreshed because the Activity is getting re-created on configuration changes (screen rotations...). You could prevent the rotation of the Activity by using:
android:screenOrientation="landscape"
or
android:screenOrientation="portrait"
in the Manifest file under your map Activity.
and this way prevent it from being recreated on rotations.
Sadly the way Google Handles map refreshing issue that you are seeing by
android:configChanges="orientation|uiMode|screenSize|fontScale"
android:screenOrientation="user"
on the Activity tag in the Manifest in the Google maps application.
EDIT
I've found a better STR:
Make sure to set "Do not keep activities" in Developer options in Settings.
Open the app with a SupportMapFragment as a child fragment of another fragment.
Switch to another app
Open your app again
Notice you can't interact with the map and no animations work.
Open another screen within the app
Notice there's a single frame or so of the map with the markers drawn on screen.
I have an issue with Google Maps API v2.
I am animating the camera to zoom to a set of custom marker bitmaps rendered on a MapFragment.
On selecting one of these marker tooltips I open a geo: intent (for the Google Maps app etc.)
When the user presses back it reopens my activity with the fragment back stack rebuilt.
My issue is that it doesn't render camera animations or the markers on coming back, though there is a brief display of those markers when the user presses back to go to the previous fragment.
The GoogleMap instance has the markers, but it doesn't render them - I'm guessing because the MapFragment/MapView thinks it doesn't need to be rendered.
How do I force a render of the MapView? Failing that, how do I get the MapView to recognise that the model has changed?
The issue was to do with the way I was handling my child fragments.
Every time the parent fragment would call onCreate the children fragments would get recreated.
I did the following to handle my child fragments, but there may be a better way:
private static final String TAG_FRAGMENT_MAP = "TagFragmentMap";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
if (savedInstanceState == null) {
// create the fragments for the first time
ft.add(R.id.view_flip, new SupportMapFragment(), TAG_FRAGMENT_MAP);
ft.commit();
}
}
// ...
public void onViewStateRestored(Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
mMapFragment = (SupportMapFragment)findFragmentByTag(TAG_FRAGMENT_MAP);
}