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

每个选项卡都有自己的布局.xml文件。xml有自己的映射片段。它是应用程序第一次启动时显示的那个。

一切都很好,除了当我在制表符之间改变。如果我尝试切换回地图片段选项卡,我会得到这个错误。在其他选项卡之间切换就可以了。

这里会出什么问题呢?

这是我的主类和main.xml,以及我使用的相关类(您还将在底部找到错误日志)

主类

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

当前回答

在这个解决方案中,你不需要采取静态变量;

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());
        }
    });

}`

其他回答

另一个解决方案:

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

就是这样,如果不是null,你不需要重新初始化它,从父删除是不必要的步骤。

As mentioned by @Justin Breitfeller, @Vidar Wahlberg solution is a hack which might not work in future version of Android. @Vidar Wahlberg perfer a hack because other solution might "cause the map to be recreated and redrawn, which isn't always desirable". Map redraw could be prevented by maintaining the old map fragment, rather than creating a new instance every time. @Matt solution doesn't work for me (IllegalStateException) As quoted by @Justin Breitfeller, "You cannot inflate a layout into a fragment when that layout includes a . Nested fragments are only supported when added to a fragment dynamically."

我的解决方案:

@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;
}

在这个解决方案中,你不需要采取静态变量;

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());
        }
    });

}`

如果你只使用Vidar Wahlberg的答案,当你打开其他活动(例如)并返回到地图时,你会得到错误。或者在我的情况下打开其他活动,然后从新的活动打开地图再次(不使用后退按钮)。 但是当你结合维达尔·沃尔伯格解决方案和马特解决方案时,你将没有例外。

布局

<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();
}

全局声明SupportMapFragment对象

    private SupportMapFragment mapFragment;

在onCreateView()方法中将代码放在下面

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文件中放入下面的代码

 <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"
    />

上面的代码解决了我的问题,它的工作很好