My problem is the same as the one in the link below, but I couldn't figure out the solution. And could not work out how to ask the author what his solution was.
Fragment with map crashes when I change activity and come back to the map
My app works fine until the orientation changes, Touch works beautiful up until that point. On orientation change it redraws the MapView as it should, but as soon as the user does any onTouch action on the map it crashes the app with:
android.view.WindowManager$BadTokenException error Unable to add window --token android.view.ViewRootImpl$blahblahblah is not valid.
I'm using ActionBarSherlock with the googlemaps plugin as suggested in the same tutorial the other question used. I just don't get how I'm supposed to create a new listener for the onTouch event after the activity restarts on orientation change. I have tried just creating a new OnTouchListener to the onTouch event but as I'm unsure, and can't find any examples, I haven't been able to guess my way to get a working Touch interface on the MapView again.
I'm sure it's something simple I'm missing.
The code I have:
public MainActivity extends SherlockFragmentActivity {
private MapView mapView;
private MapFragment mMapFragment;
public void onCreate(Bundle savedInstanceState){
View view = getLayoutInflater().inflate(R.layout.mapLayout, null);
mapView = (MapView)view.findViewById(R.id.map);
mapView.setBuiltInZoomControls(true);
setContentView(R.layout.activity_main);
}
public void onResume(){
setupFragments();
}
private void setupFragments(){
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
mMapFragment = (MapFragment) getSupportFragmentManager().findFragmentByTag(MapFragment.TAG);
if (mMapFragment == null){
mMapFragment = new MapFragment(mapView);
ft.add(R.id.fragment_container, mMapFragment, MapFragment.TAG);
}
ft.show(mMapFragment);
ft.commit();
}
}
public class MapFragment extends SherlockFragment{
public static final String TAG = "MapFragment";
private MapView mapView;
private MapOverlay itemizedOverlay;
public MapFragment(MapView mapView){
this.mapView=mapView;
}
public void onResume(){
super.onResume();
List<Overlay> mapOverlays = mapView.getOverlays();
itemizedOverlay(defaultActiveRoad, mapView.getContext());
mapOverlays.add(itemizedOverlay);
}
public View onCreateView(LayoutInflater inflater, ViewGroup vg, Bundle savedInstanceBundle){
super.onCreateView(inflater,vg,savedInstanceBundle);
return mapView;
}
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
}
public void onDestroyView(){
super.onDestroyView();
((ViewGroup)mapView.getParent()).removeView(mapView);
}
public void setMapView (MapView mapView){
this.mapView = mapView;
}
public MapView getMapView(){
return mapView;
}
}
The error log contains
android.view.WindowManager$BadTokenException: Unable to add window -- token android.view.ViewRootImpl$W#40fab3b0 is not valid; is your activity running?
at android.view.ViewRootImpl.setView(ViewRootImpl.java:585)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:326)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:224)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:149)
at android.view.Window$LocalWindowManager.addView(Window.java:547)
at android.widget.ZoomButtonsController.setVisible(ZoomButtonsController.java:371)
at com.google.android.maps.MapView.displayZoomControls(MapView.java:1055)
at com.google.android.maps.MapView$1.onDown(MapView.java:341)
at com.google.android.maps.GestureDetector.onTouchEvent(GestureDetector.java:517)
at com.google.android.maps.MapView.onTouchEvent(MapView.java:685)
After hitting my head against a wall for a few days, I decided to upgrade the map system to Google Maps Android API v2. This has solved the problem I was having with the zoom controls.
After following the instructions on: Using ActionBarSherlock With the New SupportMapFragment
I created a SherlockMapFragment as instructed in the instructions above, but in my app package. My MapFragment now extends the new SherlockMapFragment just created.
public class MapFragment extends SherlockMapFragment {
public static final String TAG = "MapFragment";
private GoogleMap mapView;
private Application global;
public MapFragment(){
}
public void onCreate(Bundle savedInstanceBundle){
super.onCreate(savedInstanceBundle);
setRetainInstance(true);
}
public void onResume(){
super.onResume();
global = (Application)getSherlockActivity().getApplication();
}
public View onCreateView(LayoutInflater inflater, ViewGroup vg, Bundle savedInstanceBundle){
View view=super.onCreateView(inflater, vg, savedInstanceBundle);
mapView = getMap();
return view;
}
}
Related
my application started crashing after the implementation of google maps into a separate tab in my android application. i have looked through all other classes and logcat and deemed those classes to lightweight to be causing this issue.
here is my maps class
public class FragmentShouts_Maps extends Fragment implements OnMapReadyCallback {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Get the view from fragment shouts.xml
View view = inflater.inflate(R.layout.fragmentshouts_maps, container, false);
SupportMapFragment fragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.maps);
if (fragment!= null) {
fragment.getMapAsync(this);
}
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onMapReady (GoogleMap googleMap) {
}
}
i've noticed when i use an emulator with a lower dpi and without google play my application will make it to this tab but will be stopped and ended. on newer api(23) with google play services it wont even make it that far, once i swipe away from the home tab, it becomes unresponsive and ends.
i have no error codes so should work once i implement the doinbackground method i believe i just dont understand how to implement this?
Don't know whats wrong with your code but I implemented google maps in my app and it works just fine. See if this is the kind of doInBackground implementation you are looking for. Hope this helps.
public class MapActivity extends Activity implements OnMapReadyCallback{
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
MapFragment mapFragment = (MapFragment)getFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(final GoogleMap map){
// Your Code
AsyncTask<String,Void,String> asyncTask = new AsyncTask<String,Void,String>(){
#Override
protected String doInBackground(String... params) {
// Do Something
}
#Override
protected void onPostExecute(String json) {
// Do Something
}
};
asyncTask.execute(url);
}
}
I've got an app which is quite intensive in terms of memory and i'm trying to get all I can. I've noticed something which I can't work out, Google maps is keeping its allocation of memory even after (I think) i'm getting rid of it.
Before Google Maps is called:
After Google Maps is called:
Returned from Google Maps with back button:
Returned from Google Maps with on info window press button:
(the slightly higher number is just due to the fact I included a couple of methods more to include a marker to return)
As you can see, it's retaining a lot of the memory. So i'll show you how this is working:
Google Maps is not actually called, but a container for Google Maps is, and it's below:
public class GoogleMapsAndBookmarksContainer extends ActionBarActivity {
private FragmentTabHost mTabHost;
public ArrayList frameListContainer;
public HashMap<String, HashMap> bookmarkInfo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_google_maps_and_bookmarks_container);
frameListContainer = (ArrayList) getIntent().getSerializableExtra("arrayListWithFrameAttributes");
bookmarkInfo = (HashMap) getIntent().getSerializableExtra("hashmapWithBookmarks");
mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), android.R.id.tabcontent);
// The first tab is the google maps fragment which i'll include below
mTabHost.addTab(
mTabHost.newTabSpec("tab1").setIndicator("Google Maps", null),
GoogleMapsFragment.class, null);
mTabHost.addTab(
mTabHost.newTabSpec("tab2").setIndicator("Bookmarks", null),
BookmarksFragment.class, null);
}
#Override
protected void onDestroy() {
super.onDestroy();
/// **** THIS WAS JUST ADDED A LOSS FOR WHAT IT COULD BE RETAINING ****
mTabHost = null;
frameListContainer = null;
bookmarkInfo = null;
}
// access for fragments
public HashMap getBookmarkInfo(){
return bookmarkInfo;
}
public ArrayList getFrameAttributesArrayList(){
return frameListContainer;
}
}
I managed to remove everything from my class but this and still the problem remain:
public class GoogleMapsFragment extends Fragment {
private GoogleMap map;
private SupportMapFragment mapFragment;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_google_maps, container, false);
FragmentManager fm = getChildFragmentManager();
mapFragment = (SupportMapFragment) fm.findFragmentById(R.id.map);
mapFragment.getMapAsync(new OnMapReadyCallback() {
public void onMapReady(GoogleMap googleMap) {
map = googleMap;
initMap();
}
});
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// frameListContainer = ((GoogleMapsAndBookmarksContainer) this.getActivity()).getFrameAttributesArrayList();
// bookmarkInfo = ((GoogleMapsAndBookmarksContainer) this.getActivity()).getBookmarkInfo();
// markerToFrameAndRoute = new HashMap<Marker, String[]>();
}
#Override
public void onDestroy() {
super.onDestroy();
mapFragment = null;
System.gc();
map = null; // I did add this in an edit, but it was mistakenly taken away when I was cutting it up, sorry
}
}
So, is this solvable? I can't work out what it is that it's retaining. I did notice if I keep going back on Google Maps and off it, it is garbage collecting it, so it's not a memory leak.
edit: have tried map.clear(); still keeps the memory
Just clear map
#Override
public void onDestroy() {
super.onDestroy();
map.clear();
}
One probable solution to this problem may be to use a retained fragment using setRetainInstance(boolean retain). In this process the map fragment wont destroy and recreate itself dumping a lot of memory, instead it will just retain the memory when it is needed, when you switch map fragment back and forth (by pressing back button).
public class RetainMapActivity extends FragmentActivity {
private GoogleMap mMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.basic_demo);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
if (savedInstanceState == null) {
// First incarnation of this activity.
mapFragment.setRetainInstance(true);
} else {
// Reincarnated activity. The obtained map is the same map instance in the previous
// activity life cycle. There is no need to reinitialize it.
mMap = mapFragment.getMap();
}
setUpMapIfNeeded();
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
if (mMap == null) {
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
if (mMap != null) {
setUpMap();
}
}
}
private void setUpMap() {
mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
}
Another solution to this may be to use a Otto event bus which is designed to decouple different parts of your application while still allowing them to communicate efficiently.
Hope this Helps!!
I am trying to get google maps v2 working in my app. I have seen several examples showing how you can open up SupportMapFragment inside an activity. The idea being that your activity will call setContentView(R.layout.map_layout); where map_layout.xml links to the fragment with the lines:
android:name="com.google.android.gms.maps.SupportMapFragment"
xmlns:map="http://schemas.android.com/apk/res-auto"
The "name=" line effectively says that "this layout is to be controlled by a fragment of type 'SupportMapFragment'".
My complication is that I am attempting to get the map to appear in an activity with tabs (implemented with actionbarsherlock). This means that whatever fragment corresponds to a tab selection must implement a TabListener. But SupportMapFragment doesn't. So now presumably I need to create a new fragment like so:
public class MyMapFragmentWithTabListener extends SupportMapFragment implements TabListener
{
But now I have got all confused about how to write the contents of MapFragmentWithTabListener in particular onCreateView... should I be inflating some layout? Surely I can't be inflating exactly the same map_layout.xml from the examples because that already declares that it is controlled by SupportMapFragment, whereas in this implementation it should be controlled by MyMapFragmentWithTabListener - do I need a slightly different xml file to inflate (if so, what should it look like?) - or should I be creating my view programatically?
I've done this in quite a few applications now. Instead of extending SupportMapFragment, you just create your own MapFragment. You can have your own layout, with a MapView view inside of it. The key is to route the lifecycle events of the Fragment to the MapView, and bobs your uncle.
Heres some example code:
MapFragment
package com.example.testapplication;
import java.util.concurrent.TimeUnit;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.MapsInitializer;
public class TestMapFragment extends Fragment {
private MapView mMapView;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.home_fragment, container, false);
mMapView = (MapView) view.findViewById(R.id.mapview);
// inflat and return the layout
mMapView.onCreate(savedInstanceState);
mMapView.onResume();// needed to get the map to display immediately
try {
MapsInitializer.initialize(getActivity());
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
GoogleMap googleMap = mMapView.getMap();
googleMap.getUiSettings().setMyLocationButtonEnabled(true);
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
/*
* Using a mapview in a fragment requires you to 'route'
* the lifecycle events of the fragment to the mapview
*/
#Override
public void onResume() {
super.onResume();
if (null != mMapView)
mMapView.onResume();
}
#Override
public void onPause() {
super.onPause();
if (null != mMapView)
mMapView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
if (null != mMapView)
mMapView.onDestroy();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (null != mMapView)
mMapView.onSaveInstanceState(outState);
}
#Override
public void onLowMemory() {
super.onLowMemory();
if (null != mMapView)
mMapView.onLowMemory();
}
}
And the layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.google.android.gms.maps.MapView
android:id="#+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:uiZoomControls="false" />
</RelativeLayout>
You can used this way.
public class NewActivity extends FragmentActivity {
private GoogleMap mMap;
SupportMapFragment mapFragment;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activit);
mapFragment = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
if(isGooglePlayServicesIsInstalled(mContext)){
mMap = mapFragment.getMap();
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
mMap.getUiSettings().setCompassEnabled(true);
mMap.getUiSettings().setZoomControlsEnabled(true);
}else{
//display any toast message
//Global.Toast("Please First install Google Maps");
}
public static boolean isGooglePlayServicesIsInstalled(Context context){
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
if (resultCode == ConnectionResult.SUCCESS)
return true;
else
return false;
}
Please check it out all the permission,api key and require all the thing.if you getting any error log then put as a comment.
I'm trying to add a MapFragment to my current Fragment. The use of nested fragments is restricted to FragmentTransactions, you can't use the xml tag in your layout.
Also, I want it to be added to the main Fragment when the user presses a button. So, I'm creating the MapFragment programmatically with getInstance() when the user presses that button and adding it to the proper place. It is shown correctly, so far so good.
The problem is that after attaching the MapFragment I need to get a reference to GoogleMap to place a Marker, but the getMap() method returns null (as the fragment's onCreateView() hasn't been called yet).
I looked at the demo example code and I found the solution they use is initializing the MapFragment in onCreate() and getting the reference to GoogleMap in onResume(), after onCreateView() has been called.
I need to get the reference to GoogleMap right after the MapFragment initialization, because I want the users to be able to show or hide the map with a button. I know a possible solution would be to create the Map at the start as said above and just set it's visibility gone, but I want the map to be off by default so it doesn't take the user's bandwidth if they don't explicitly asked for it.
I tried with the MapsInitializer, but doesn't work either. I'm kind of stuck. Any ideas?
Here is my testing code so far:
public class ParadaInfoFragment extends BaseDBFragment {
// BaseDBFragment is just a SherlockFragment with custom utility methods.
private static final String MAP_FRAGMENT_TAG = "map";
private GoogleMap mMap;
private SupportMapFragment mMapFragment;
private TextView mToggleMapa;
private boolean isMapVisible = false;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_parada_info, container, false);
mToggleMapa = (TextView) v.findViewById(R.id.parada_info_map_button);
return v;
}
#Override
public void onStart() {
super.onStart();
mToggleMapa.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!isMapVisible) {
openMap();
} else {
closeMap();
}
isMapVisible = !isMapVisible;
}
});
}
private void openMap() {
// Creates initial configuration for the map
GoogleMapOptions options = new GoogleMapOptions().camera(CameraPosition.fromLatLngZoom(new LatLng(37.4005502611301, -5.98233461380005), 16))
.compassEnabled(false).mapType(GoogleMap.MAP_TYPE_NORMAL).rotateGesturesEnabled(false).scrollGesturesEnabled(false).tiltGesturesEnabled(false)
.zoomControlsEnabled(false).zoomGesturesEnabled(false);
// Modified from the sample code:
// It isn't possible to set a fragment's id programmatically so we set a
// tag instead and search for it using that.
mMapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentByTag(MAP_FRAGMENT_TAG);
// We only create a fragment if it doesn't already exist.
if (mMapFragment == null) {
// To programmatically add the map, we first create a
// SupportMapFragment.
mMapFragment = SupportMapFragment.newInstance(options);
// Then we add it using a FragmentTransaction.
FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.parada_info_map_container, mMapFragment, MAP_FRAGMENT_TAG);
fragmentTransaction.commit();
}
// We can't be guaranteed that the map is available because Google Play
// services might not be available.
setUpMapIfNeeded(); //XXX Here, getMap() returns null so the Marker can't be added
// The map is shown with the previous options.
}
private void closeMap() {
FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
fragmentTransaction.remove(mMapFragment);
fragmentTransaction.commit();
}
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the
// map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
mMap = mMapFragment.getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
mMap.addMarker(new MarkerOptions().position(new LatLng(37.4005502611301, -5.98233461380005)).title("Marker"));
}
}
}
}
Thanks
The good AnderWebs gave me an answer in Google+ but he is too laz.... emm busy to write it here again, so here is the short version:
Extend the MapFragment class and override the onCreateView() method. After this method is done we can get a non-null reference to que GoogleMap object.
This is my particular solution:
public class MiniMapFragment extends SupportMapFragment {
private LatLng mPosFija;
public MiniMapFragment() {
super();
}
public static MiniMapFragment newInstance(LatLng posicion){
MiniMapFragment frag = new MiniMapFragment();
frag.mPosFija = posicion;
return frag;
}
#Override
public View onCreateView(LayoutInflater arg0, ViewGroup arg1, Bundle arg2) {
View v = super.onCreateView(arg0, arg1, arg2);
initMap();
return v;
}
private void initMap(){
UiSettings settings = getMap().getUiSettings();
settings.setAllGesturesEnabled(false);
settings.setMyLocationButtonEnabled(false);
getMap().moveCamera(CameraUpdateFactory.newLatLngZoom(mPosFija,16));
getMap().addMarker(new MarkerOptions().position(mPosFija).icon(BitmapDescriptorFactory.fromResource(R.drawable.marker)));
}
}
Now in the previous Fragment class I do
mMapFragment = MiniMapFragment.newInstance(new LatLng(37.4005502611301, -5.98233461380005));
Maybe it's not perfect yet, because the screen blinks when showing the map. But not sure if the problem is because of this or something else.
Thanks, found this very helpful. Am posting my slightly modified solution, as it was cleaner for me to tell the parent Fragment when the map was ready. This method also works with a saveInstanceState / restoreInstanceState cycle.
public class CustomMapFragment extends SupportMapFragment {
private static final String LOG_TAG = "CustomMapFragment";
public CustomMapFragment() {
super();
}
public static CustomMapFragment newInstance() {
CustomMapFragment fragment = new CustomMapFragment();
return fragment;
}
#Override
public View onCreateView(LayoutInflater arg0, ViewGroup arg1, Bundle arg2) {
View v = super.onCreateView(arg0, arg1, arg2);
Fragment fragment = getParentFragment();
if (fragment != null && fragment instanceof OnMapReadyListener) {
((OnMapReadyListener) fragment).onMapReady();
}
return v;
}
/**
* Listener interface to tell when the map is ready
*/
public static interface OnMapReadyListener {
void onMapReady();
}
}
To use as a nested Fragment:-
public class ParentFragment extends Fragment implements OnMapReadyListener {
...
mMapFragment = CustomMapFragment.newInstance();
getChildFragmentManager().beginTransaction().replace(R.id.mapContainer, mMapFragment).commit();
#Override
public void onMapReady() {
mMap = mMapFragment.getMap();
}
...
}
Hope it helps someone.
Here's my solution to this, I took inspiration from the code previously posted and cleaned it up. I also added the static methods with and without the GoogleMapOptions parameters.
public class GoogleMapFragment extends SupportMapFragment {
private static final String SUPPORT_MAP_BUNDLE_KEY = "MapOptions";
public static interface OnGoogleMapFragmentListener {
void onMapReady(GoogleMap map);
}
public static GoogleMapFragment newInstance() {
return new GoogleMapFragment();
}
public static GoogleMapFragment newInstance(GoogleMapOptions options) {
Bundle arguments = new Bundle();
arguments.putParcelable(SUPPORT_MAP_BUNDLE_KEY, options);
GoogleMapFragment fragment = new GoogleMapFragment();
fragment.setArguments(arguments);
return fragment;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (OnGoogleMapFragmentListener) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException(getActivity().getClass().getName() + " must implement OnGoogleMapFragmentListener");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
if (mCallback != null) {
mCallback.onMapReady(getMap());
}
return view;
}
private OnGoogleMapFragmentListener mCallback;
}
The usage pattern is as follows:
public class MyMapActivity implements OnGoogleMapFragmentListener {
...
#Override
public void onMapReady(GoogleMap map) {
mUIGoogleMap = map;
...
}
...
private GoogleMap mUIGoogleMap;
}
No need to cutomize SupportMapFragment you can do this directly by using following piece of code,
FragmentManager fm = getSupportFragmentManager(); // getChildFragmentManager inside fragments.
CameraPosition cp = new CameraPosition.Builder()
.target(initialLatLng) // your initial co-ordinates here. like, LatLng initialLatLng
.zoom(zoom_level)
.build();
SupportMapFragment mapFragment = SupportMapFragment.newInstance(new GoogleMapOptions().camera(cp));
fm.beginTransaction().replace(R.id.rl_map, mapFragment).commit();
Add this piece of code for layout
<RelativeLayout
android:id="#+id/rl_map"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
This will load GoogleMap at particular Location directly i.e, initialLatLng.
am using the android support v4- google maps by pete doyle and am trying to delete a mapview and then recreate it again, when i go away from and return to it, but i keep getting the usual Java.lang.IllegalStateException: You are only allowed to have a single MapView in a MapActivity. anyone know ho to solve this correctly. I have this code in my fragment.
Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Log.d(TAG, "onCreate View called here in location fragment!!");
if(view == null){
view = inflater.inflate(R.layout.map, container, false);
frame = (FrameLayout)view.findViewById(R.id.mapContainer);
//mapview = (MapView)view.findViewById(R.id.mapView);
}
if(mapview == null){
mapview = new MapView(getActivity(), getActivity().getString(R.string.map_api_key)); // keep getting the error on this line
mapview_is_active = true;
}
mapview.setClickable(true);
mapview.setBuiltInZoomControls(true);
mapview.setSatellite(true); // Satellite View
mapview.setStreetView(true); // Street View
mapview.setTraffic(true); // Traffic View
frame.addView(mapview,0);
//frame = (FrameLayout)view.findViewById(R.id.mapContainer);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
if(mapview == null){
Log.d(TAG, "mapview is null here");
mapview = new MapView(getActivity(), getActivity().getString(R.string.map_api_key));
}
if(frame.getChildAt(0) == null){
Log.d(TAG, "mapview is null here in container");
frame.addView(mapview);
}
MapController controller = mapview.getController();
double lat = Double.parseDouble(longitude);
double lon = Double.parseDouble(latitude);
GeoPoint geopoint = new GeoPoint((int)(lat * 1E6), (int)(lon * 1E6));
mapview.invalidate();
List<Overlay> mapOverlays = mapview.getOverlays();
Drawable drawable = this.getResources().getDrawable(R.drawable.map_point);
AddMapOverlay add_map_overlay = new AddMapOverlay(drawable, getActivity());
OverlayItem overlayitem = new OverlayItem(geopoint, name, address);
add_map_overlay.addOverlay(overlayitem);
mapOverlays.add(add_map_overlay);
controller.animateTo(geopoint);
controller.setZoom(15);
}
and in my onStop():
#Override
public void onStop(){
super.onStop();
if(frame != null){
frame.removeView(mapview); // i remove the mapview here
}
}
here is my map.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mapContainer"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1">
</FrameLayout>
any help will be greatly appreciated. Thanks
I did this with the below code. I have a MapView instance variable in my FragmentActivity, and then added and removed it in the Fragment itself below (just included the pertinent parts):
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mLayoutMap = (FrameLayout) getActivity().findViewById(R.id.layoutMap);
// create the map view if it's not already there
if (((MyActivity)getActivity()).mMapView == null)
{
((MyActivity)getActivity()).mMapView =
new MapView(getActivity(), getActivity().getString(R.string.map_api_key));
((MyActivity)getActivity()).mMapView.setClickable(true);
}
// add the map view to the frame layout, at the lowest z-index
mLayoutMap.addView(((MyActivity)getActivity()).mMapView, 0);
}
#Override
public void onStop()
{
super.onStop();
if (mLayoutMap.getChildCount() > 0 && mLayoutMap.getChildAt(0) instanceof MapView)
mLayoutMap.removeViewAt(0);
}
mLayoutMap is just a FrameLayout in my XML.
Usually I did this (use android-support-v4-google_maps as you):
1) Implement to activity interface like IMapActivity with methods of attachMap and detachMap
public class MyMapActivity extends FragmentActivity implements IMapActivity {
private MapView mMapView;
public void attachMap(ViewGroup mapHolder) {
if (mMapView == null) {
mMapView = getLayoutInflater().inflate(R.id.mapview, null);
}
mapHolder.addView(mMapView);
}
public void detachMap(ViewGroup mapHolder) {
mapHolder.removeView(mMapView);
}
}
2) Call that methods when need to attach MapView or detach MapView on Fragment.onDestroyView()
public class MyMapFragment extends Fragment {
private IMapActivity mMapViewHolder;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mMapViewHolder = (IMapActivity) activity;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mMapViewHolder.attachMap(getMapHolder());
}
#Override
public void onDestroyView() {
mMapViewHolder.detachMap(getMapHolder());
super.onDestroyView();
}
}
I keep in a separate xml MapView with the some settings. When it is necessary to destroy the Fragment - detach MapView, attach MapView when the Fragment is recreated (you can also update the controller of MapView after the attach). This allows me to reuse fragments MapView.
P.S.
I just have not found any way how to clean MapActivity of links to the MapViev. If there is a way, I would be very grateful.
Try using frame.removeAllViews()
If you are working with navHost, you need to add it programmatically not in XML because it will be duplicated.
val mapFragment = SupportMapFragment.newInstance()
requireActivity().supportFragmentManager
.beginTransaction()
.add(R.id.mapFragment, mapFragment)
.commit()