Android:导航抽屉+片段+ NestedFragment + SupportMapFragment

时间:2014-10-16 03:59:19

标签: android android-fragments navigation-drawer supportmapfragment

过去两天我一直在阅读stackoverflow上的所有可能的线程,我无法弄清楚我的问题在哪里......每次我带来一个"修复&#34时遇到一个新的错误;

在代码之前,结束状态:我试图在多个片段之间设置导航抽屉。其中一个是餐馆搜索,以SupportMapFragment显示搜索结果。

当我第一次加载包含地图的片段时,我没有收到错误,但是当我切换到另一个片段时,由于NavigationDrawer而出现错误,当我发现错误时,我收到了错误消息。按下后退按钮,加上许多其他好东西。

这是我的代码:

NavigationDrawer.java

public class NavigationDrawerActivity extends FragmentActivity {
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    private ActionBarDrawerToggle mDrawerToggle;

    private CharSequence mDrawerTitle;
    private CharSequence mTitle;
    private String[] mListFragments;

    public static FragmentManager fragmentManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        fragmentManager = getSupportFragmentManager();

        mTitle = mDrawerTitle = getTitle();
        mListFragments = new String[] {"Search","Feed","About","Test"};
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);

        // set a custom shadow that overlays the main content when the drawer opens
        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
        // set up the drawer's list view with items and click listener
        mDrawerList.setAdapter(new ArrayAdapter<String>(this,
                R.layout.drawer_list_item, mListFragments));
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

        // enable ActionBar app icon to behave as action to toggle nav drawer
        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);

        // ActionBarDrawerToggle ties together the the proper interactions
        // between the sliding drawer and the action bar app icon
        mDrawerToggle = new ActionBarDrawerToggle(
                this,                  /* host Activity */
                mDrawerLayout,         /* DrawerLayout object */
                R.drawable.ic_drawer,  /* nav drawer image to replace 'Up' caret */
                R.string.drawer_open,  /* "open drawer" description for accessibility */
                R.string.drawer_close  /* "close drawer" description for accessibility */
        ) {
            public void onDrawerClosed(View view) {
                getActionBar().setTitle(mTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }

            public void onDrawerOpened(View drawerView) {
                getActionBar().setTitle(mDrawerTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }
        };
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        if (savedInstanceState == null) {
            selectItem(0);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.navigation_drawer, menu);
        return super.onCreateOptionsMenu(menu);
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // The action bar home/up action should open or close the drawer.
        // ActionBarDrawerToggle will take care of this.
        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        // Handle action buttons
        switch(item.getItemId()) {
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    public void Logout(MenuItem item) {
        SharedPreferences settings = getSharedPreferences(App.PREFS_NAME, 0);

        settings.edit().remove("email").apply();
        settings.edit().remove("password").apply();
        settings.edit().remove("userID").apply();
        settings.edit().putBoolean("hasLoggedIn",false).apply();
        Intent intent = new Intent(this,LoginActivity.class);
        startActivity(intent);
    }

    /* The click listner for ListView in the navigation drawer */
    private class DrawerItemClickListener implements ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            selectItem(position);
        }
    }

    Fragment fragment;

    private void selectItem(int position) {
        // update the main content by replacing fragments
        switch (position){
            // Search engine
//            case 0:
//                if ( fragment!=null) fragment.onDestroy();
//                fragment = new RestaurantSearchFragment();
//                break;
            // Rating feed
            case 1:
//                fragment = new RatingFeedTabHostFragment();
//                break;
            // About screen
            case 2:
                fragment = new AboutFragment();
                break;
            case 3:
                fragment = new RestaurantSearchFragment2();
                break;
            default:
                fragment = new AboutFragment();
                break;
        }


        fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();

        // update selected item and title, then close the drawer
        mDrawerList.setItemChecked(position, true);
        setTitle(mListFragments[position]);
        mDrawerLayout.closeDrawer(mDrawerList);
    }

    @Override
    public void setTitle(CharSequence title) {
        mTitle = title;
        getActionBar().setTitle(mTitle);
    }

    /**
     * When using the ActionBarDrawerToggle, you must call it during
     * onPostCreate() and onConfigurationChanged()...
     */

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Pass any configuration change to the drawer toggls
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

}

fragment_restaurant_search.xml

<!-- Your layouts-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">
    <!--The content you want to add-->
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_action_search_dark"
            android:layout_gravity="center"
            android:id="@+id/icon_search"/>
        <AutoCompleteTextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:singleLine="true"
            android:hint="Enter Restaurant Name"
            android:id="@+id/restaurant_search"
            android:completionThreshold="1"
            android:imeOptions="actionSearch"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/button_search"
            android:text="Go!"
            />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_action_location_found"
            android:id="@+id/location_search_image"
            android:layout_gravity="center"
            />

        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"

            android:hint="Near Current Location"
            android:singleLine="true"
            android:imeOptions="actionSearch"
            android:id="@+id/location_search"
            android:inputType="none"/>
    </LinearLayout>


    <fragment xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.SupportMapFragment"/>


    <fragment android:name="com.bestpick.bestpickapplication.Screens.NavigationDrawer.RestaurantSearch.RestaurantsListFragment"
        android:id="@+id/restaurant_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:layout="@layout/fragment_restaurants"
        />

</LinearLayout>

RestaurantSearchFragment2.java

public class RestaurantSearchFragment2 extends Fragment
{
    // Handles to UI widgets
    private EditText locationSearchText;
    private AutoCompleteTextView restaurantSearch;

    private FragmentActivity context;

    // sets context from calling Navigation Drawer Activity (FragmentActivity)
    @Override
    public void onAttach(Activity activity) {
        context=(FragmentActivity) activity;
        super.onAttach(activity);
    }


    public static FragmentManager fragmentManager;
    private RestaurantMapFragment restaurantMapFragment;
    private RestaurantsListFragment restaurantsListFragment;



    @Override
    public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){

        View view = inflater.inflate(R.layout.fragment_restaurant_search, container, false);

        fragmentManager = getChildFragmentManager();

        // setting up the restaurant list fragment
        restaurantsListFragment = (RestaurantsListFragment) fragmentManager.findFragmentById(R.id.restaurant_fragment);
        if (restaurantsListFragment == null) {
            restaurantsListFragment = new RestaurantsListFragment();
            fragmentManager.beginTransaction().replace(R.id.restaurant_fragment, restaurantsListFragment).commit();
        }

        // setting up the restaurant map fragment
        restaurantMapFragment = (RestaurantMapFragment) fragmentManager.findFragmentById(R.id.map);
        if (restaurantMapFragment==null){
            restaurantMapFragment = new RestaurantMapFragment();
            fragmentManager.beginTransaction().replace(R.id.map,restaurantMapFragment).commit();
        }
        return view;
    }
}

RestaurantFragmentMap.java

public class RestaurantMapFragment extends Fragment {

    private static View view;
    /**
     * Note that this may be null if the Google Play services APK is not
     * available.
     */

    private static GoogleMap mMap;
    private static Double latitude, longitude;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        if (container == null) {
            return null;
        }
        view = (RelativeLayout) inflater.inflate(R.layout.location_fragment, container, false);
        // Passing harcoded values for latitude & longitude. Please change as per your need. This is just used to drop a Marker on the Map
        latitude = 26.78;
        longitude = 72.56;

        setUpMapIfNeeded(); // For setting up the MapFragment

        return view;
    }

    /***** Sets up the map if it is possible to do so *****/
    public static 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 = ((SupportMapFragment) NavigationDrawerActivity.fragmentManager
                    .findFragmentById(R.id.location_map)).getMap();
            // Check if we were successful in obtaining the map.
            if (mMap != null)
                setUpMap();
        }
    }

    /**
     * This is where we can add markers or lines, add listeners or move the
     * camera.
     * <p>
     * This should only be called once and when we are sure that {@link #mMap}
     * is not null.
     */
    private static void setUpMap() {
        // For showing a move to my loction button
        mMap.setMyLocationEnabled(true);
        // For dropping a marker at a point on the Map
        mMap.addMarker(new MarkerOptions().position(new LatLng(latitude, longitude)).title("My Home").snippet("Home Address"));
        // For zooming automatically to the Dropped PIN Location
        mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(latitude,
                longitude), 12.0f));
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {

        if (mMap != null)
            setUpMap();

        if (mMap == null) {
            // Try to obtain the map from the SupportMapFragment.
            mMap = ((SupportMapFragment) NavigationDrawerActivity.fragmentManager
                    .findFragmentById(R.id.location_map)).getMap();
            // Check if we were successful in obtaining the map.
            if (mMap != null)
                setUpMap();
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();

        try {
            Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
            childFragmentManager.setAccessible(true);
            childFragmentManager.set(this, null);

        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**** The mapfragment's id must be removed from the FragmentManager
     **** or else if the same it is passed on the next time then
     **** app will crash ****/
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (mMap != null) {

            RestaurantSearchFragment2.fragmentManager.beginTransaction()
                    .remove(RestaurantSearchFragment2.fragmentManager.findFragmentById(R.id.location_map)).commitAllowingStateLoss();
            mMap = null;
        }
    }
}

location_fragment.xml

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

    <fragment
        android:id="@+id/location_map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.google.android.gms.maps.SupportMapFragment" />

</RelativeLayout>

我遇到了世界上所有的错误,我现在最喜欢的是:

10-15 23:39:45.786    6568-6568/com.bestpick.bestpickapplication E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.bestpick.bestpickapplication, PID: 6568
    java.lang.NullPointerException
            at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:651)
            at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1484)
            at android.support.v4.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.java:1937)
            at android.support.v4.app.Fragment.performDestroy(Fragment.java:1721)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1071)
            at android.support.v4.app.FragmentManagerImpl.removeFragment(FragmentManager.java:1218)
            at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:639)
            at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1484)
            at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:450)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5017)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
            at dalvik.system.NativeStart.main(Native Method)

10-15 23:34:54.866    6251-6251/com.bestpick.bestpickapplication E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.bestpick.bestpickapplication, PID: 6251
    java.lang.RuntimeException: Unable to destroy activity {com.bestpick.bestpickapplication/com.bestpick.bestpickapplication.Screens.NavigationDrawer.NavigationDrawerActivity}: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
            at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3497)
            at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3515)
            at android.app.ActivityThread.access$1400(ActivityThread.java:135)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1249)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5017)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
            at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1360)
            at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1378)
            at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
            at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
            at com.bestpick.bestpickapplication.Screens.NavigationDrawer.RestaurantSearch.RestaurantMapFragment.onDestroyView(RestaurantMapFragment.java:120)
            at android.support.v4.app.Fragment.performDestroyView(Fragment.java:1709)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1011)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1121)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1103)
            at android.support.v4.app.FragmentManagerImpl.dispatchDestroyView(FragmentManager.java:1932)
            at android.support.v4.app.Fragment.performDestroyView(Fragment.java:1706)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1011)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1121)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1103)
            at android.support.v4.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.java:1938)
            at android.support.v4.app.FragmentActivity.onDestroy(FragmentActivity.java:336)
            at android.app.Activity.performDestroy(Activity.java:5403)
            at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1117)
            at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3484)
            at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3515)
            at android.app.ActivityThread.access$1400(ActivityThread.java:135)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1249)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5017)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
            at dalvik.system.NativeStart.main(Native Method)

我用Google搜索了所有内容,阅读了博客,stackoverflow ......仍然无法弄清楚任何事情!

感谢您的支持

1 个答案:

答案 0 :(得分:0)

为背压做这个....

@Override
public void onBackPressed(){
    android.support.v4.app.FragmentManager fm = this.getSupportFragmentManager();

    if(fm.getBackStackEntryCount() > 0) {
        fm.popBackStack();
    }
    else {


    }

}