使用com.google.android.gms.maps.MapFragment的其他片段复制ID,标记空值或父级ID

我有一个三个选项卡的应用程序。

每个选项卡都有自己的布局.xml文件。 main.xml有自己的地图片段。 这是应用程序首次启动时显示的那个。

一切工作正常,除了当我改变选项卡之间。 如果我尝试切换回地图片段选项卡,我得到这个错误。 切换到其他标签和之间工作得很好。

这里有什么可能是错的?

这是我的主类,我的main.xml,以及我使用的相关类(你也可以在底部find错误日志)

主要类

package com.nfc.demo; import android.app.ActionBar; import android.app.ActionBar.Tab; import android.app.Activity; import android.app.Fragment; import android.app.FragmentTransaction; import android.os.Bundle; import android.widget.Toast; public class NFCDemoActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActionBar bar = getActionBar(); bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); bar.addTab(bar .newTab() .setText("Map") .setTabListener( new TabListener<MapFragment>(this, "map", MapFragment.class))); bar.addTab(bar .newTab() .setText("Settings") .setTabListener( new TabListener<SettingsFragment>(this, "settings", SettingsFragment.class))); bar.addTab(bar .newTab() .setText("About") .setTabListener( new TabListener<AboutFragment>(this, "about", AboutFragment.class))); if (savedInstanceState != null) { bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0)); } // setContentView(R.layout.main); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("tab", getActionBar().getSelectedNavigationIndex()); } public static class TabListener<T extends Fragment> implements ActionBar.TabListener { private final Activity mActivity; private final String mTag; private final Class<T> mClass; private final Bundle mArgs; private Fragment mFragment; public TabListener(Activity activity, String tag, Class<T> clz) { this(activity, tag, clz, null); } public TabListener(Activity activity, String tag, Class<T> clz, Bundle args) { mActivity = activity; mTag = tag; mClass = clz; mArgs = args; // Check to see if we already have a fragment for this tab, // probably from a previously saved state. If so, deactivate // it, because our initial state is that a tab isn't shown. mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag); if (mFragment != null && !mFragment.isDetached()) { FragmentTransaction ft = mActivity.getFragmentManager() .beginTransaction(); ft.detach(mFragment); ft.commit(); } } public void onTabSelected(Tab tab, FragmentTransaction ft) { if (mFragment == null) { mFragment = Fragment.instantiate(mActivity, mClass.getName(), mArgs); ft.add(android.R.id.content, mFragment, mTag); } else { ft.attach(mFragment); } } public void onTabUnselected(Tab tab, FragmentTransaction ft) { if (mFragment != null) { ft.detach(mFragment); } } public void onTabReselected(Tab tab, FragmentTransaction ft) { Toast.makeText(mActivity, "Reselected!", Toast.LENGTH_SHORT) .show(); } } } 

main.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" > <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mapFragment" android:name="com.google.android.gms.maps.MapFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> 

相关类(MapFragment.java)

 package com.nfc.demo; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class MapFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); return inflater.inflate(R.layout.main, container, false); } public void onDestroy() { super.onDestroy(); } } 

错误

 android.view.InflateException: Binary XML file line #7: Error inflating class fragment at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704) at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) at android.view.LayoutInflater.inflate(LayoutInflater.java:489) at android.view.LayoutInflater.inflate(LayoutInflater.java:396) at com.nfc.demo.MapFragment.onCreateView(MapFragment.java:15) at android.app.Fragment.performCreateView(Fragment.java:1695) at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:885) at android.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1255) at android.app.BackStackRecord.run(BackStackRecord.java:672) at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1435) at android.app.FragmentManagerImpl$1.run(FragmentManager.java:441) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5039) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.IllegalArgumentException: Binary XML file line #7: Duplicate id 0x7f040005, tag null, or parent id 0xffffffff with another fragment for com.google.android.gms.maps.MapFragment at android.app.Activity.onCreateView(Activity.java:4722) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:680) ... 19 more 

马特build议的答案是有效的,但它会导致地图被重新创build和重画,这并不总是令人满意的。 经过大量的反复试验,我发现了一个适合我的解决scheme:

 private static View view; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (view != null) { ViewGroup parent = (ViewGroup) view.getParent(); if (parent != null) parent.removeView(view); } try { view = inflater.inflate(R.layout.map, container, false); } catch (InflateException e) { /* map is already there, just return view as it is */ } return view; } 

为了更好的衡量,这里的“map.xml”(R.layout.map)和R.id.mapFragment(android:id =“@ + id / mapFragment”):

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mapLayout" android:layout_width="match_parent" android:layout_height="match_parent" > <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mapFragment" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.SupportMapFragment" /> </LinearLayout> 

我希望这有帮助,但我不能保证它没有任何不利影响。

编辑:有一些不利的影响,如退出应用程序,并再次启动。 由于应用程序不一定完全closures(但只是睡在后台),我以前提交的代码将重新启动应用程序失败。 我已经将代码更新为适合我的东西,既进出地图,退出并重新启动应用程序,我对try-catch位也不太满意,但似乎工作得很好。 在查看堆栈跟踪时,我发现我只能检查映射片段是否在FragmentManager中,不需要try-catch块,代码已更新。

更多的编辑:事实certificate,你需要尝试赶上。 毕竟,只是检查地图片段结果并不是很好。 Blergh。

问题是你所要做的不该做。 你不应该在其他碎片内部膨胀碎片。 从Android的文档 :

注意:当布局包含<fragment>时,不能将布局充气到碎片中。 只有在dynamic添加到片段时才支持嵌套片段。

虽然你可以用这里介绍的黑客完成任务,但我强烈build议你不要这样做。 不可能确定这些黑客将处理每个新的Android操作系统当你尝试膨胀包含另一个片段的片段的布局。

唯一由Android支持的将片段添加到另一个片段的方法是通过来自子片段pipe理器的事务。

只需将您的XML布局更改为一个空的容器(如果需要,添加一个ID):

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mapFragmentContainer" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > </LinearLayout> 

然后在Fragment onViewCreated(View view, @Nullable Bundle savedInstanceState)方法中:

 @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); FragmentManager fm = getChildFragmentManager(); SupportMapFragment mapFragment = (SupportMapFragment) fm.findFragmentByTag("mapFragment"); if (mapFragment == null) { mapFragment = new SupportMapFragment(); FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.mapFragmentContainer, mapFragment, "mapFragment"); ft.commit(); fm.executePendingTransactions(); } mapFragment.getMapAsync(callback); } 

我有同样的问题,并能够通过手动删除Fragment类的onDestroy()方法中的MapFragment来解决它。 这里是工作的代码,并在XML中通过ID引用MapFragment

 @Override public void onDestroyView() { super.onDestroyView(); MapFragment f = (MapFragment) getFragmentManager() .findFragmentById(R.id.map); if (f != null) getFragmentManager().beginTransaction().remove(f).commit(); } 

如果您不手动删除MapFragment ,则它将四处移动,以免花费大量资源重新创build/显示地图视图。 看起来保持底层的MapView非常适合在标签之间来回切换,但在片段中使用时,这种行为会导致在具有相同ID的每个新的MapFragment上创build重复的MapView 。 解决方法是手动删除MapFragment ,从而在每次片段膨胀时重新创build底层映射。

我还在另一个答案中注意到了这一点[ 1 ]。

这是我的答案:

1,创build一个如下的布局xml:

 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/map_container" android:layout_width="match_parent" android:layout_height="match_parent"> </FrameLayout> 

2,在Fragment类中,以编程方式添加Google地图。

 import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.SupportMapFragment; import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; /** * A simple {@link android.support.v4.app.Fragment} subclass. Activities that * contain this fragment must implement the * {@link MapFragment.OnFragmentInteractionListener} interface to handle * interaction events. Use the {@link MapFragment#newInstance} factory method to * create an instance of this fragment. * */ public class MapFragment extends Fragment { // TODO: Rename parameter arguments, choose names that match private GoogleMap mMap; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_map, container, false); SupportMapFragment mMapFragment = SupportMapFragment.newInstance(); mMap = mMapFragment.getMap(); FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); transaction.add(R.id.map_container, mMapFragment).commit(); return view; } @Override public void onAttach(Activity activity) { super.onAttach(activity); Log.d("Attach", "on attach"); } @Override public void onDetach() { super.onDetach(); } } 
  1. 正如@Justin Breitfeller所说,@Vidar Wahlberg解决scheme是一种在未来的Android版本中可能不起作用的黑客攻击。
  2. @维达·沃尔伯格认为这是一种黑客行为,因为其他解决scheme可能会“导致地图被重新创build和重绘,而这并不总是令人满意的”。 可以通过维护旧的地图片段来防止地图重绘,而不是每次都创build一个新的实例。
  3. @Matt解决scheme对我不起作用(IllegalStateException)
  4. 正如@Justin Breitfeller所引用的,“当布局包含一个布局时,不能将布局膨胀成一个片段,只有在dynamic添加片段时才支持嵌套片段。

我的解决scheme

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_map_list, container, false); // init //mapFragment = (SupportMapFragment)getChildFragmentManager().findFragmentById(R.id.map); // don't recreate fragment everytime ensure last map location/state are maintain if (mapFragment == null) { mapFragment = SupportMapFragment.newInstance(); mapFragment.getMapAsync(this); } FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); // R.id.map is a layout transaction.replace(R.id.map, mapFragment).commit(); return view; } 

我会build议在你的标签处理中使用replace()而不是attach() / detach()

或者,切换到ViewPager 。 这里是一个示例项目,显示一个ViewPager ,带有标签,托pipe10个地图。

我今天已经失去了几个小时来find原因,幸好这个问题并不是因为MapFragment的实现,不幸的是,这是行不通的,因为嵌套的片段只能通过第11版的支持库来支持。

我的实现有一个带有两个选项卡(无viewpager)的操作栏(标签模式)的活动,一个具有地图,另一个具有条目列表。 当然,我在我的标签片段中使用MapFragment已经相当天真了,等我每次切换回地图标签时,应用程序都会崩溃。

(同样的问题,我也会有我的选项卡片段将膨胀包含任何其他片段的布局)。

一种select是使用MapView(而不是MapFragment),虽然有一些开销(参见MapView Docs作为layout.xml中的插件replace,但另一种select是从版本11开始使用support-library,但是采用编程方法因为嵌套的片段不是通过布局来支持的,或者只是通过明确地销毁片段(比如在Matt / Vidar的回答中)来编程,btw:使用MapView(选项1)可以达到同样的效果。

但实际上,我不想在每次退出时都放松地图,也就是说,我只想在活动结束时将其保留在内存中,因此我决定在Tab键时隐藏/显示地图,请参阅FragmentTransaction / hide

对于那些仍然遇到这个问题的人来说,最好的方法是确保你不会在一个Tab中的Map中得到这个错误,那就是让这个Fragment扩展SupportMapFragment而不是在用于Tab的Fragment中嵌套一个SupportMapFragment

我刚刚使用带有FragmentPagerAdapterViewPager和第三个Tab中的SupportMapFragment。

这里是一般的结构,注意不需要重写onCreateView()方法,也不需要膨胀任何布局xml:

 public class MapTabFragment extends SupportMapFragment implements OnMapReadyCallback { private GoogleMap mMap; private Marker marker; public MapTabFragment() { } @Override public void onResume() { super.onResume(); setUpMapIfNeeded(); } private void setUpMapIfNeeded() { if (mMap == null) { getMapAsync(this); } } @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; setUpMap(); } private void setUpMap() { mMap.setMyLocationEnabled(true); mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID); mMap.getUiSettings().setMapToolbarEnabled(false); mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() { @Override public void onMapClick(LatLng point) { //remove previously placed Marker if (marker != null) { marker.remove(); } //place marker where user just clicked marker = mMap.addMarker(new MarkerOptions().position(point).title("Marker") .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA))); } }); } } 

结果:

在这里输入图像说明

以下是我用来testing的完整类代码,其中包括用于前两个Tabs的占位符Fragment和用于第三个Tab的Map Fragment:

 public class MainActivity extends AppCompatActivity implements ActionBar.TabListener{ SectionsPagerAdapter mSectionsPagerAdapter; ViewPager mViewPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); // Set up the ViewPager with the sections adapter. mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mSectionsPagerAdapter); final ActionBar actionBar = getSupportActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { actionBar.setSelectedNavigationItem(position); } }); for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) { actionBar.addTab(actionBar.newTab().setText(mSectionsPagerAdapter.getPageTitle(i)).setTabListener(this)); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } @Override public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { mViewPager.setCurrentItem(tab.getPosition()); } @Override public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { } @Override public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { } public class SectionsPagerAdapter extends FragmentPagerAdapter { public SectionsPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { switch (position) { case 0: return PlaceholderFragment.newInstance(position + 1); case 1: return PlaceholderFragment.newInstance(position + 1); case 2: return MapTabFragment.newInstance(position + 1); } return null; } @Override public int getCount() { // Show 3 total pages. return 3; } @Override public CharSequence getPageTitle(int position) { Locale l = Locale.getDefault(); switch (position) { case 0: return getString(R.string.title_section1).toUpperCase(l); case 1: return getString(R.string.title_section2).toUpperCase(l); case 2: return getString(R.string.title_section3).toUpperCase(l); } return null; } } public static class PlaceholderFragment extends Fragment { private static final String ARG_SECTION_NUMBER = "section_number"; TextView text; public static PlaceholderFragment newInstance(int sectionNumber) { PlaceholderFragment fragment = new PlaceholderFragment(); Bundle args = new Bundle(); args.putInt(ARG_SECTION_NUMBER, sectionNumber); fragment.setArguments(args); return fragment; } public PlaceholderFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); text = (TextView) rootView.findViewById(R.id.section_label); text.setText("placeholder"); return rootView; } } public static class MapTabFragment extends SupportMapFragment implements OnMapReadyCallback { private static final String ARG_SECTION_NUMBER = "section_number"; private GoogleMap mMap; private Marker marker; public static MapTabFragment newInstance(int sectionNumber) { MapTabFragment fragment = new MapTabFragment(); Bundle args = new Bundle(); args.putInt(ARG_SECTION_NUMBER, sectionNumber); fragment.setArguments(args); return fragment; } public MapTabFragment() { } @Override public void onResume() { super.onResume(); Log.d("MyMap", "onResume"); setUpMapIfNeeded(); } private void setUpMapIfNeeded() { if (mMap == null) { Log.d("MyMap", "setUpMapIfNeeded"); getMapAsync(this); } } @Override public void onMapReady(GoogleMap googleMap) { Log.d("MyMap", "onMapReady"); mMap = googleMap; setUpMap(); } private void setUpMap() { mMap.setMyLocationEnabled(true); mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID); mMap.getUiSettings().setMapToolbarEnabled(false); mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() { @Override public void onMapClick(LatLng point) { Log.d("MyMap", "MapClick"); //remove previously placed Marker if (marker != null) { marker.remove(); } //place marker where user just clicked marker = mMap.addMarker(new MarkerOptions().position(point).title("Marker") .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA))); Log.d("MyMap", "MapClick After Add Marker"); } }); } } } 

另一个scheme

 if (view == null) { view = inflater.inflate(R.layout.nearbyplaces, container, false); } 

就是这样,如果不是null,则不需要重新初始化,从父项中移除是不必要的步骤。

在全局声明SupportMapFragment对象

  private SupportMapFragment mapFragment; 

在onCreateView()方法下面input代码

 mapFragment = (SupportMapFragment) getChildFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); 

在onDestroyView()把下面的代码

 @Override public void onDestroyView() { super.onDestroyView(); if (mapFragment != null) getFragmentManager().beginTransaction().remove(mapFragment).commit(); } 

在你的xml文件中input下面的代码

  <fragment android:id="@+id/map" android:name="com.abc.Driver.fragment.FragmentHome" class="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> 

上面的代码解决了我的问题,它工作正常

我尊重所有的答案,但我发现这一个class轮解决scheme:如果n是选项卡数然后:

  mViewPager.setOffscreenPageLimit(n); 

例如:如上所述:

  mViewPager.setOffscreenPageLimit(2); 

查看寻呼机实现一个队列,所以你不必让它去除那个片段。 onCreateView只被调用一次。

目前不支持嵌套片段。 尝试支持包,修订版11 。

你是否试图在布局文件中引用自定义的MapFragment类?

 <?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" > <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mapFragment" android:name="com.nfc.demo.MapFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> 

如果您仅使用Vidar Wahlberg答案,则当您打开其他活动(例如)并返回到地图时会出错。 或者在我的情况下打开其他活动,然后从新的活动再次打开地图(不使用后退button)。 但是,如果将Vidar Wahlberg解决scheme和Matt解决scheme结合使用,则不会有例外。

布局

 <com.example.ui.layout.MapWrapperLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/map_relative_layout"> <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/root"> <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.SupportMapFragment" /> </RelativeLayout> </<com.example.ui.layout.MapWrapperLayout> 

分段

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { setHasOptionsMenu(true); if (view != null) { ViewGroup parent = (ViewGroup) view.getParent(); if (parent != null){ parent.removeView(view); } } try { view = inflater.inflate(R.layout.map_view, null); if(view!=null){ ViewGroup root = (ViewGroup) view.findViewById(R.id.root); ... @Override public void onDestroyView() { super.onDestroyView(); Fragment fragment = this.getSherlockActivity().getSupportFragmentManager().findFragmentById(R.id.map); if (fragment != null) getFragmentManager().beginTransaction().remove(fragment).commit(); } 

我有这viewPager和崩溃是因为任何片段必须有自己的标签,重复标签或ids相同的片段是不允许的。

我认为以前的App-Compat lib中的子Fragment存在一些bug。 我试过@维达·沃尔伯格和@马特的答案,他们不为我工作。 更新appcompat库后,我的代码运行完美无需任何额外的努力。

这里要注意的是,你的应用程序将在两种情况下严重崩溃: –

1)为了再次使用Maps的片段MapView片段必须被删除,当你的片段显示地图被replace为onDestroyViewcallback中的其他片段。

否则,当你尝试膨胀相同的片段两次重复的ID,标签为空,或父母的ID与com.google.android.gms.maps.MapFragment错误的另一个片段将会发生。

2)其次,你不能将app.Fragment操作与android.support.v4.app.Fragment API操作混合使用eg.do不要使用android.app.FragmentTransaction去除v4.app.Fragmenttypes的MapView Fragment。 混合这将再次导致从片段一侧崩溃。

这里是正确使用MapView的示例代码片段

 import android.content.Context; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.GoogleMap.OnMapClickListener; import com.google.android.gms.maps.MapFragment; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MarkerOptions; import com.serveroverload.yago.R; /** * @author 663918 * */ public class HomeFragment extends Fragment implements LocationListener { // Class to do operations on the Map GoogleMap googleMap; private LocationManager locationManager; public static Fragment newInstance() { return new HomeFragment(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.home_fragment, container, false); Bundle bdl = getArguments(); // setuping locatiomanager to perfrom location related operations locationManager = (LocationManager) getActivity().getSystemService( Context.LOCATION_SERVICE); // Requesting locationmanager for location updates locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 1, 1, this); // To get map from MapFragment from layout googleMap = ((MapFragment) getActivity().getFragmentManager() .findFragmentById(R.id.map)).getMap(); // To change the map type to Satellite // googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE); // To show our current location in the map with dot // googleMap.setMyLocationEnabled(true); // To listen action whenever we click on the map googleMap.setOnMapClickListener(new OnMapClickListener() { @Override public void onMapClick(LatLng latLng) { /* * LatLng:Class will give us selected position lattigude and * longitude values */ Toast.makeText(getActivity(), latLng.toString(), Toast.LENGTH_LONG).show(); } }); changeMapMode(2); // googleMap.setSatellite(true); googleMap.setTrafficEnabled(true); googleMap.setBuildingsEnabled(true); googleMap.setMyLocationEnabled(true); return v; } private void doZoom() { if (googleMap != null) { googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom( new LatLng(18.520430, 73.856744), 17)); } } private void changeMapMode(int mapMode) { if (googleMap != null) { switch (mapMode) { case 0: googleMap.setMapType(GoogleMap.MAP_TYPE_NONE); break; case 1: googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL); break; case 2: googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE); break; case 3: googleMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN); break; case 4: googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID); break; default: break; } } } private void createMarker(double latitude, double longitude) { // double latitude = 17.385044; // double longitude = 78.486671; // lets place some 10 random markers for (int i = 0; i < 10; i++) { // random latitude and logitude double[] randomLocation = createRandLocation(latitude, longitude); // Adding a marker MarkerOptions marker = new MarkerOptions().position( new LatLng(randomLocation[0], randomLocation[1])).title( "Hello Maps " + i); Log.e("Random", "> " + randomLocation[0] + ", " + randomLocation[1]); // changing marker color if (i == 0) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_AZURE)); if (i == 1) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_BLUE)); if (i == 2) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_CYAN)); if (i == 3) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_GREEN)); if (i == 4) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)); if (i == 5) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_ORANGE)); if (i == 6) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_RED)); if (i == 7) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_ROSE)); if (i == 8) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_VIOLET)); if (i == 9) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_YELLOW)); googleMap.addMarker(marker); // Move the camera to last position with a zoom level if (i == 9) { CameraPosition cameraPosition = new CameraPosition.Builder() .target(new LatLng(randomLocation[0], randomLocation[1])) .zoom(15).build(); googleMap.animateCamera(CameraUpdateFactory .newCameraPosition(cameraPosition)); } } } /* * creating random postion around a location for testing purpose only */ private double[] createRandLocation(double latitude, double longitude) { return new double[] { latitude + ((Math.random() - 0.5) / 500), longitude + ((Math.random() - 0.5) / 500), 150 + ((Math.random() - 0.5) * 10) }; } @Override public void onLocationChanged(Location location) { if (null != googleMap) { // To get lattitude value from location object double latti = location.getLatitude(); // To get longitude value from location object double longi = location.getLongitude(); // To hold lattitude and longitude values LatLng position = new LatLng(latti, longi); createMarker(latti, longi); // Creating object to pass our current location to the map MarkerOptions markerOptions = new MarkerOptions(); // To store current location in the markeroptions object markerOptions.position(position); // Zooming to our current location with zoom level 17.0f googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(position, 17f)); // adding markeroptions class object to the map to show our current // location in the map with help of default marker googleMap.addMarker(markerOptions); } } @Override public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub } @Override public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } @Override public void onProviderDisabled(String provider) { // TODO Auto-generated method stub } @Override public void onDestroyView() { // TODO Auto-generated method stub super.onDestroyView(); locationManager.removeUpdates(this); android.app.Fragment fragment = getActivity().getFragmentManager() .findFragmentById(R.id.map); if (null != fragment) { android.app.FragmentTransaction ft = getActivity() .getFragmentManager().beginTransaction(); ft.remove(fragment); ft.commit(); } } } 

XML

  <fragment android:id="@+id/map" android:name="com.google.android.gms.maps.MapFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> 

Result looks like this :- 在这里输入图像说明

Hope it will help Somebody.

In this solution you do not need to take static variable;

 Button nextBtn; private SupportMapFragment mMapFragment; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); if (mRootView != null) { ViewGroup parent = (ViewGroup) mRootView.getParent(); Utility.log(0,"removeView","mRootView not NULL"); if (parent != null) { Utility.log(0, "removeView", "view removeViewed"); parent.removeAllViews(); } } else { try { mRootView = inflater.inflate(R.layout.dummy_fragment_layout_one, container, false);// } catch (InflateException e) { /* map is already there, just return view as it is */ e.printStackTrace(); } } return mRootView; } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); FragmentManager fm = getChildFragmentManager(); SupportMapFragment mapFragment = (SupportMapFragment) fm.findFragmentById(R.id.mapView); if (mapFragment == null) { mapFragment = new SupportMapFragment(); FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.mapView, mapFragment, "mapFragment"); ft.commit(); fm.executePendingTransactions(); } //mapFragment.getMapAsync(this); nextBtn = (Button) view.findViewById(R.id.nextBtn); nextBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Utility.replaceSupportFragment(getActivity(),R.id.dummyFragment,dummyFragment_2.class.getSimpleName(),null,new dummyFragment_2()); } }); }` 
 <?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" > <com.google.android.gms.maps.MapView android:id="@+id/mapview" android:layout_width="100dip" android:layout_height="100dip" android:layout_alignParentTop="true" android:layout_alignRight="@+id/textView1" android:layout_marginRight="15dp" > </com.google.android.gms.maps.MapView> 

Why don't you insert a map using the MapView object instead of MapFragment ? I am not sure if there is any limitation in MapView,though i found it helpful.