I have a MainActivity which has an ActionBar with two tab, the first tab is to show the sensor data value and the second tab I want to show the Map.
But I have a problem to implement the map in the fragment on the second tab
The MainActivity is shown as below:
public class MainActivity extends Activity
{
private static final String DATA_FRAGMENT_BAR = "Data";
private static final String MAP_FRAGMENT_BAR = "Map";
private DataCollection mDataCollection;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Config.mContext = this;
ActionBar actionBar = getActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME| ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab dataTab = actionBar.newTab().setText(DATA_FRAGMENT_BAR);
ActionBar.Tab mapTab = actionBar.newTab().setText(MAP_FRAGMENT_BAR);
Fragment dataFragment = new FragmentData();
Fragment mapFragment = new FragmentMap();
dataTab.setTabListener(new MyTabsListener(dataFragment));
mapTab.setTabListener(new MyTabsListener(mapFragment));
actionBar.addTab(dataTab);
actionBar.addTab(mapTab);
mDataCollection = DataCollection.getInstance();
}
....
}
The TabsListener is shown as below
public class MyTabsListener implements ActionBar.TabListener
{
private Fragment fragment;
public MyTabsListener(Fragment fragment)
{
this.fragment = fragment;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
ft.replace(R.id.fragment_container, fragment);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
ft.remove(fragment);
}
}
The the map fragment class is shown as below:
public class FragmentMap extends Fragment
{
MapView mapView;
GoogleMap map;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.fragment_map, container, false);
// Gets the MapView from the XML layout and creates it
mapView = (MapView) v.findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
// Gets to GoogleMap from the MapView and does initialization stuff
map = mapView.getMap();
//map.getUiSettings().setMyLocationButtonEnabled(false);
//map.setMyLocationEnabled(true);
map.addMarker(new MarkerOptions().position(new LatLng(50.167003,19.383262)));
// Needs to call MapsInitializer before doing any CameraUpdateFactory calls
try
{
MapsInitializer.initialize(this.getActivity());
}
catch (GooglePlayServicesNotAvailableException e)
{
e.printStackTrace();
}
// Updates the location and zoom of the MapView
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(43.1, -87.9), 10);
map.animateCamera(cameraUpdate);
return v;
}
#Override
public void onResume()
{
mapView.onResume();
super.onResume();
}
#Override
public void onDestroy()
{
super.onDestroy();
mapView.onDestroy();
}
#Override
public void onLowMemory()
{
super.onLowMemory();
mapView.onLowMemory();
}
}
I set a break point in the FragmentMap class at the line "mapView.onCreate(savedInstanceState);" the savedInstanceState is null and the program will crash after line.
Can someone help. Thanks in advance.
Google released the Map API Version 2. This gives you a MapFragment and a SupportMapFragment. This allows you to add a Map without extending MapActivity.
Google Maps v2 In fragment cashes when clicked twice
It is not really clear in the documentation, but the MapView.onCreate() method should be called in the Fragment.onActivityCreated(), not in Fragment.onCreate()
Also, MapView.getMap() can return null, don't forget to check with that.
And you should call super.onResume() before mapView.onResume()
Related
I am creating an App where I want to switch between my CustomMapFragment and a ListFragment. If I start the App and call replaceFragment:
private void replaceFragment(final Fragment fragment) {
final FragmentManager fragmentManager = mActivity.getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.main_content_frame, fragment)
.commit();
}
with replaceFragment(new CustomMapFragment()) the Map looks like it should.
The CustomMapFragment is a Fragment where I replace a FrameLayout with the native MapFragment, to have it separated from the code.
If I call the replace method again on button click or something, with a different Fragment (the ListFragment for example), the FrameLayout gets replaced with this, everything is fine.
If I now try to replace it again with the CustomMapFragment, the exact same call like on the beginning, the Map is loaded but it is missing every Marker and every Setting I have done in the CustomMapFragment.
CustomMapFragment:
public class CustomMapFragment extends BaseFragment {
private static final String LOG_TAG = PosMapFragment.class.getSimpleName();
private MapFragment mMapFragment;
private GoogleMap mMap;
private ImageLoader mImageLoader;
private Context mContext;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity();
final RequestQueue reqQueue = Volley.newRequestQueue(mContext);
mImageLoader = new ImageLoader(reqQueue, new BitmapLruCache(mContext));
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.maps_fragment, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mMapFragment = MapFragment.newInstance();
replaceFragment(mMapFragment);
}
private void postMapInitialisation() {
new View(getActivity()).post(new Runnable() {
#Override
public void run() {
addTestMarker(0, 0, "http://www.jimis-cyberstore.com/store/media/gp_batman_tshirts.jpg");
addTestMarker(10, 10, "http://img.netzwelt.de/software/icons/2012/8842/android-sdk.png");
addTestMarker(50, 50, "http://fs02.androidpit.info/ali/x84/4053084-1374511678988-80x80.png");
addTestMarker(5, 0, "http://im.wk.io/images/77e3e40/kitkat-chromium-ubernimmt-in-android.jpeg");
addTestMarker(0, 10, "http://www.mchme.de/cms/kategorien/18_Software/dateien/fb_logo_80.jpg");
addTestMarker(15, 5, "http://navigator.ptvgroup.com/uploads/pics/PTV_Navigator_Android_Windows2_80x80px_01.png");
}
});
}
#Override
public void onResume() {
super.onResume();
setUpMapIfNeeded();
postMapInitialisation();
EventBusProvider.getInstance().register(this);
}
private void replaceFragment(final Fragment fragment) {
final FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.maps, fragment)
.commit();
}
private void setUpMapIfNeeded() {
if (mMap == null) {
mMap = mMapFragment.getMap();
if (mMap != null) {
mMap.setMyLocationEnabled(true);
mMap.setInfoWindowAdapter(this);
mMap.setOnInfoWindowClickListener(this);
}
}
}
private void addTestMarker(final double lat, final double lng, String url){
if(mMap != null){
final NetworkImageMarker networkImageMarker = new NetworkImageMarker(mContext, url);
final Marker marker = mMap.addMarker(networkImageMarker.getMarkerOptions(lat, lng, mImageLoader));
networkImageMarker.setMarker(marker);
networkImageMarker.setReloadListener(new OnReloadListener() {
#Override
public void reAddNetworkImageMarker(Bitmap bitmap) {
mMap.addMarker(networkImageMarker.getMarkerOptions(lat, lng, bitmap));
}
});
}
}
#Subscribe
public void onLocationChanged(final LocationChangedEvent event) {
centerMap(event.mLocation);
}
private void centerMap(Location location){
double latitude = location.getLatitude();
double longitude = location.getLongitude();
LatLng latLng = new LatLng(latitude, longitude);
centerMapAtLocation(latLng);
}
private void centerMapAtLocation(LatLng location) {
mMap.moveCamera(CameraUpdateFactory.newLatLng(location));
mMap.animateCamera(CameraUpdateFactory.zoomTo(14));
}
}
The main layout is just a FrameLayout, which get replaced for different Fragments. I also tried to load just one Fragment where the CustomMapFragment and the ListFragment are loaded at the same time, with two FrameLayouts, so they are stacked over each other, but it ends up in the same behavior.
It seems there is something wrong with the MapFragment (not the SupportMapFragment).
loading MapFragment at the beginning = MapFragment looks perfect
MapFragment -> ListFragment -> MapFragment = MapFragment is an empty Map
ListFragment -> MapFragment = MapFragment is an empty Map
MapFragment -> MapFragment = MapFragment is an empty Map
Because you are trying to replace fragments inside of another fragment, you should use getChildFragmentManager() instead of getFragmentManager() in your replace method.
private void replaceFragment(final Fragment fragment) {
final FragmentManager fragmentManager = getChildFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.maps, fragment)
.commit();
}
Unfortunately getChildFragmentManager() is only supported for api lvl >= 17, so you will probably have to use the android-support-v4 library.
In my application there is a fragment activity containing three tabs(map,list,settings). I have put remove and commit at onPause() method of map tab(extends fragment). When i toggle between tabs, it is working fine but when I move to next page(next activity) and come back, it throws nullpointer exception.
Because when I switch to next activity, onPause() map fragment has been removed and committed and when comes back it found it null and throws exception. I am unable to figure out, where to place my onPause() method code or how to init fragment again on restart or resume.
public class LocatorMainActivity extends FragmentActivity {
public class MapSectionFragment extends Fragment {
GoogleMap map;
public MapSectionFragment() {
}
/*
* (non-Javadoc)
*
* #see android.support.v4.app.Fragment#onDestroyView()
*/
#Override
public void onDestroyView() {
// TODO Auto-generated method stub
super.onDestroyView();
Log.e("", "onDestroyView");
/*try{
Fragment fragment = (getFragmentManager()
.findFragmentById(R.id.map));
ft = getFragmentManager()
.beginTransaction();
//ft.addToBackStack(null);
ft.remove(fragment);
ft.commit();
//getFragmentManager().executePendingTransactions();
//ft.commitAllowingStateLoss();
}catch(Exception e){
Log.e("", "Exception::" + e.toString());
}*/
}
#Override
public void onPause(){
super.onPause();
Log.e("", "onPause");
try{
Fragment fragment = (getFragmentManager()
.findFragmentById(R.id.map));
ft = getFragmentManager()
.beginTransaction();
//if(ft.isAddToBackStackAllowed()){
//ft.hide(fragment);
if(ft.isAddToBackStackAllowed()){
Log.e("", "back stack allowed");
ft.remove(fragment);
//ft.addToBackStack(getTag());
//ft.addToBackStack(null);
ft.commit();
}
//}
//getFragmentManager().executePendingTransactions();
//ft.commitAllowingStateLoss();
}catch(Exception e){
Log.e("", "Exception::" + e.toString());
}
}
/*
#Override
public void onResume(){
super.onResume();
Log.e("inner", "onResume");
}*/
#Override
public void onStop() {
super.onStop();
Log.e("inner", "onStop");
//mReturningWithResult = false;
}
View rootView = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//code
});
return rootView;
}
}
}
Please suggest me where I am wrong.
Thanks.
In my working map fragment code, I've got the remove/commit of the map fragment (I'm using SupportMapFragment) within the onDestroyView() method, and I've got the initialization of the map within the onActivityCreated() method, as shown below:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getFragmentManager();
myMapFragment = (SupportMapFragment) fm.findFragmentById(R.id.id_for_your_map_fragment);
if (myMapFragment == null) {
myMapFragment = (SupportMapFragment) SupportMapFragment.newInstance();
/* Code omitted here... all you have to do here is get your
* fragment manager and run a replace() operation to swap the new fragment in
*/
}
myMap = myMapFragment.getMap();
}
#Override
public void onDestroyView () {
super.onDestroyView();
try {
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.remove(myMapFragment).commit();
}
catch (Exception e) {
e.printStackTrace();
}
}
And finally, within onResume(), I run this check to make sure that the map is not null; if it is, I run the getMap() method:
#Override
public void onResume() {
if (myMap == null) {
FragmentManager fm = getFragmentManager();
myMapFragment = (SupportMapFragment) fm.findFragmentById(R.id.id_for_your_map_fragment);
myMap = myMapFragment.getMap();
}
}
Having these snippets arranged in the places specified above has worked for me so far. I hope this helps! :)
my issue resolved by putting these code:
public class Fragment1 extends Fragment {
GoogleMap map;
#Override
public void onStart() {
// TODO Auto-generated method stub
map = ((SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map)).getMap();
super.onStart();
}
/*
* (non-Javadoc)
*
* #see android.support.v4.app.Fragment#onDestroyView()
*/
#Override
public void onDestroyView() {
// TODO Auto-generated method stub
Fragment fragment = (getFragmentManager()
.findFragmentById(R.id.map));
if (fragment.isResumed()) {
getFragmentManager().beginTransaction().remove(fragment)
.commit();
}
super.onDestroyView();
}
I am using actionbarsherlock to implement a set of tabs. One of the tabs is a fragment containing a MapView. My onCreateView is as follows:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.mapview, container, false);
mMapView = (MapView) view.findViewById(R.id.mapv);
mMapView.onCreate(savedInstanceState);
mMapView.onResume();
try
{
MapsInitializer.initialize(getActivity());
}
catch (GooglePlayServicesNotAvailableException e)
{
e.printStackTrace();
}
googleMap = mMapView.getMap();
googleMap.getUiSettings().setMyLocationButtonEnabled(true);
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(PARIS, 10));
googleMap.addMarker(new MarkerOptions().position(PARIS).title("Paris").snippet("Great city"));
return view;
}
As you can see, the map is originally displayed zoomed in on Paris, which has a Marker on it. Everything is working fine so far. I see the map and can manually drag and zoom the map. If I then press the button on the side of my phone to cause it to pause, then unlock the phone to resume, I can still drag and zoom. BUT if I switch to another tab, then come back to the map tab, I see the map as I left it, but it no longer responds to drag/zoom. It appears frozen. But no errors are being displayed in my log and I can still flip between tabs.
Without any log errors, I don't know how to track down the problem.
EDIT: I'm using Maps v2
EDIT: I've just found a similar sounding situation here. It may well be the answer, but I don't know quite where to place the code from the suggested solution.
EDIT: Just in case the critical code was not in my snippet, here's the whole thing...
package com.mycompany.myapp;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import com.actionbarsherlock.app.ActionBar.Tab;
import com.actionbarsherlock.app.ActionBar.TabListener;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import android.view.View;
public class TestMapFragment extends Fragment implements TabListener
{
private Fragment mFragment;
private MapView mMapView;
private GoogleMap googleMap;
private static final LatLng PARIS = new LatLng(48.874,2.347);
#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.mapview, container, false);
mMapView = (MapView) view.findViewById(R.id.mapv);
mMapView.onCreate(savedInstanceState);
mMapView.onResume();
try
{
MapsInitializer.initialize(getActivity());
}
catch (GooglePlayServicesNotAvailableException e)
{
e.printStackTrace();
}
googleMap = mMapView.getMap();
googleMap.getUiSettings().setMyLocationButtonEnabled(true);
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(PARIS, 10));
googleMap.addMarker(new MarkerOptions().position(PARIS).title("Paris").snippet("Great city"));
return view;
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft)
{
mFragment = new TestMapFragment();
ft.add(android.R.id.content, mFragment);
ft.attach(mFragment);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
/*
* 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 (mMapView != null)
{
mMapView.onResume();
}
}
#Override
public void onPause()
{
super.onPause();
if (mMapView != null)
{
mMapView.onPause();
}
}
#Override
public void onDestroy()
{
super.onDestroy();
if (mMapView != null)
{
mMapView.onDestroy();
}
}
#Override
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
if (mMapView != null)
{
mMapView.onSaveInstanceState(outState);
}
}
#Override
public void onLowMemory()
{
super.onLowMemory();
if (mMapView != null)
{
mMapView.onLowMemory();
}
}
}
This added line container.removeAllViewsInLayout() seems to have done the trick.
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
container.removeAllViewsInLayout();
View view = inflater.inflate(R.layout.mapview, container, false);
i also had the same problem
i have done something like this
Fragment activity which will hold the fragments
Map_main_screen.java
public class Map_main_screen extends FragmentActivity {
private static final String[] CONTENT = new String[] { "TAB one",
"Second tab GOOGLE MAP", };
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.map_new);
FragmentPagerAdapter adapter = new GoogleMusicAdapter(
getSupportFragmentManager());
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(adapter);
TabPageIndicator indicator = (TabPageIndicator)findViewById(R.id.indicator);
indicator.setViewPager(pager);
==========================new_class_GoogleMusicAdapter============================
class GoogleMusicAdapter extends FragmentPagerAdapter {
public GoogleMusicAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return Map_google_TestFragment.newInstance(CONTENT[position
% CONTENT.length]);
}
#Override
public CharSequence getPageTitle(int position) {
return CONTENT[position % CONTENT.length].toUpperCase();
}
#Override
public int getCount() {
return CONTENT.length;
}
}
// =================adapter ends here===============================
}
Map_google_TestFragment.java
public final class Map_google_TestFragment extends Fragment {
private static final String KEY_CONTENT = "TestFragment:Content";
Typeface tf;
public static Map_google_TestFragment newInstance(String content) {
Map_google_TestFragment fragment = new Map_google_TestFragment();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 1; i++) {
builder.append(content).append(" ");
}
builder.deleteCharAt(builder.length() - 1);
fragment.mContent = builder.toString();
return fragment;
}
private String mContent = "???";
private int[] mICONS = { 1 };
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if ((savedInstanceState != null)
&& savedInstanceState.containsKey(KEY_CONTENT)) {
mContent = savedInstanceState.getString(KEY_CONTENT);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
LayoutInflater vi = (LayoutInflater) getActivity().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
View v;
if (mContent.toString().equals("TAB one")) {
v = vi.inflate(R.layout.YOUR_SECOND_LAYOUT, null);
//***************************************
// function related to your first fragment
//***************************************
} else {
//***************************************
// inflate your Google map layout here
// function related to your Second fragment
//***************************************
View view = inflater.inflate(R.layout.mapview, container, false); //INFLATE GOOGLE MAP LAYOUT
mMapView = (MapView) view.findViewById(R.id.mapv);
mMapView.onCreate(savedInstanceState);
mMapView.onResume();
try
{
MapsInitializer.initialize(getActivity());
}
catch (GooglePlayServicesNotAvailableException e)
{
e.printStackTrace();
}
googleMap = mMapView.getMap();
googleMap.getUiSettings().setMyLocationButtonEnabled(true);
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(PARIS, 10));
googleMap.addMarker(new MarkerOptions().position(PARIS).title("Paris").snippet("Great city"));
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_CONTENT, mContent);
}
}
Have you tried using mMapView.displayZoomControls(true) right after mMapView = (MapView) view.findViewById(R.id.mapv)?
I have a question and a problem. First of all I don't know is this possible:
I have a fragment activity with tabs. On one tab (which is a fragment) I have a map with a hidden list of items. Map is putted in a frame of that fragment. The list is downloaded and on a button press is visible again. On a map I have markers that represents that items.
My problem is this: I always get map to be null when a use getMap() from a fragment that I put in a frame.
Is this possible? And if not what do you recommend? Thanks in advance.
EDITED
public class MapExplore extends Fragment{
private FrameLayout frame;
private ListView list;
private String api_key;
private GoogleMap map;
private MapExploreAdapter adapter;
private SupportMapFragment map_fragment;
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
api_key = Configuration.get_prefereence_string(getActivity(), "user_activation_key", null);
adapter = new MapExploreAdapter();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.map_explore, null);
frame = (FrameLayout) view.findViewById(R.id.frameMap);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
setUpMapFragment();
}
private void setUpMapFragment(){
if(map_fragment == null){
map_fragment = SupportMapFragment.newInstance();
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.add(frame.getId(), map_fragment, Utils.MAP_FRAGMENT_TAG);
ft.commit();
}
}
private void setUpMap(){
Log.i("SET UP MAP", "Started");
if(map == null){
map = ((SupportMapFragment) map_fragment).getMap();
}
if(map != null){
map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(Utils.SF_LAT, Utils.SF_LON), 13));
}
}
#Override
public void onResume() {
// TODO Auto-generated method stub
super.onResume();
setUpMap();
}
I edited my question with some code...
If you could post some of you code it would be easier to diagnose your problem:
meantime try creating your SupportMap fragment dynamically as follows:
mMapFragment = new SupportMapFragment() {
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
GoogleMap map = mMapFragment.getMap();
if (map != null) {
//Your initialization code goes here
}
}
};
Altenative approach to use Mapview inside fragment as follows:
public class Yourfragment extends Fragment {
private MapView mMapView;
private GoogleMap mMap;
private Bundle mBundle;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View inflatedView = inflater.inflate(R.layout.map_fragment, container, false);
try {
MapsInitializer.initialize(getActivity());
} catch (GooglePlayServicesNotAvailableException e) {
// TODO handle this situation
}
mMapView = (MapView) inflatedView.findViewById(R.id.map);
mMapView.onCreate(mBundle);
setUpMapIfNeeded(inflatedView);
return inflatedView;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBundle = savedInstanceState;
}
private void setUpMapIfNeeded(View inflatedView) {
if (mMap == null) {
mMap = ((MapView) inflatedView.findViewById(R.id.map)).getMap();
if (mMap != null) {
setUpMap();
}
}
}
private void setUpMap() {
mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
}
#Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
#Override
public void onDestroy() {
mMapView.onDestroy();
super.onDestroy();
}
}
And put map view in XML as follows:
<com.google.android.gms.maps.MapView
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Here is a link to the official documentation for MapView
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.