85.simo
85.simo

Reputation: 1

Sliding Drawer with ViewPager causing blank fragments

I'm using an Activity with a Drawer Layout, which I need for switching between different Fragments. One of these Fragments is making use of a ViewPager with a FragmentStateViewPagerAdapter, which I need to use for implementing the Swipe Views behavior between different PreferenceFragments. Everything works fine at first: I launch the app, the first Fragment is correctly shown (the one that doesn't make use of the ViewPager). Even using the sliding drawer to move to the second Fragment (the ViewPager's one) works. But then, if I go back to the first Fragment and I try to open the second Fragment again, all I get is a blank screen! It still shows the tabs in the action bar and the ViewPager is still working, but the fragment is just...blank. Furthermore, swiping pages I could notice that the second Fragment will still be blank, while the third and the following ones are correctly loaded. After doing this, I also noticed that swiping back will also make the two pages which weren't visible, correctly load. I'm getting no Exceptions and everything seems to work in the correct way, except for that. Does anyone have any idea of what might be causing this issue? I followed the Android Developers tutorial, both for DrawerLayout and for ViewPager.

Here's my code:

The Main Activity:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        homeFragment = new HomeFragment();
        swypeFragment = new SwypeTabsPreferences();


        mTitle = mDrawerTitle = getTitle();
        mSections = getResources().getStringArray(R.array.sections_array);
        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,
                mSections));
        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 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);
        }



    }
    public void onDestroy() {
        super.onDestroy();
        Log.d("DEBUG", "In Method: onDestroy()");
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }

    /*Called whenever we call invalidateOptionsMenu() */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        //If the nav drawer is open, hide action items related to the content view
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
        menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }

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

    @Override
    public void onResume() {
       super.onResume();
    }


    private class DrawerItemClickListener implements ListView.OnItemClickListener {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            selectItem(position);
        }
    }

    // Swaps fragments in the main content view
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void selectItem(int position) {
        //update the main content by replacing fragments
        if (position == 0) {
        //Fragment fragment = new HomeFragment();
        //fragment.setRetainInstance(true);

        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction trans = fragmentManager.beginTransaction();
        if (null ==fragmentManager.findFragmentByTag("home")) {
            trans.replace(R.id.content_frame, homeFragment, "home");
        }
        trans.commit();
        //update selected item and title, then close the drawer
        mDrawerList.setItemChecked(position, true);
        setTitle(mSections[position]);
        mDrawerLayout.closeDrawer(mDrawerList);
        }
        else if (position == 1) {
            //Fragment fragment = new SwypeTabsPreferences();
            //fragment.setRetainInstance(true);

            FragmentManager fragmentManager = getFragmentManager();
            FragmentTransaction trans = fragmentManager.beginTransaction();
            if (null ==fragmentManager.findFragmentByTag("swype")) {
                trans.replace(R.id.content_frame, swypeFragment, "swype");
            }
            trans.commit();

            //update selected item and title, then close the drawer
            mDrawerList.setItemChecked(position, true);
            setTitle(mSections[position]);
            mDrawerLayout.closeDrawer(mDrawerList);
        }
    else if (position == 2) {
         //TO BE DONE
       }
    }

    @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 toggle
        mDrawerToggle.onConfigurationChanged(newConfig);
    }
}

The Fragment using ViewPager:

public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            this.context = getActivity();
            this.setRetainInstance(true);



                //pager.setOffscreenPageLimit(6);
            //Specify that the Home/up button should not be enabled, since there is no hierarchical parent
            //actionBar.setHomeButtonEnabled(true)
        }

        @Override
        public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {

        }
        @Override
        public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
            //When the given tab is selected, switch to the corresponding page in the ViewPager
            pager.setCurrentItem(tab.getPosition());
        }

        @Override
        public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
        }

        /*private class MyPageAdapter extends FragmentStatePagerAdapter {
            private final String[] TITLES = context.getResources().getStringArray(R.array.settings_titles);
            private ArrayList<Fragment> fragments;

            public MyPageAdapter(FragmentManager fm, ArrayList<Fragment> fragments) {
                super(fm);
                this.fragments = fragments;
            }
            @Override
            public Fragment getItem(int position) {
                return this.fragments.get(position);
            }
            @Override
            public int getCount() {
                return this.fragments.size();
            }

            @Override
            public CharSequence getPageTitle(int position) {
                return TITLES[position % NUM_ITEMS] ;
            }

            @Override
            public int getItemPosition(Object object) {
                return POSITION_NONE;
            }
        }*/
        public abstract class MyPageAdapter extends FragmentStatePagerAdapter {

            private SparseArray<WeakReference<Fragment>> mPageReferenceMap = new SparseArray<WeakReference<Fragment>>(0);
            private List<String> mTabTitles;

            public abstract Fragment initFragment(int position);

            public MyPageAdapter(FragmentManager fm, List<String> tabTitles) {
                super(fm);
                mTabTitles = tabTitles;
            }

            @Override
            public Object instantiateItem(ViewGroup viewGroup, int position) {

                mPageReferenceMap.put(Integer.valueOf(position), new WeakReference<Fragment>(initFragment(position)));
                return super.instantiateItem(viewGroup, position);
            }

            @Override
            public int getCount() {
                return mTabTitles.size();
            }

            @Override
            public CharSequence getPageTitle(int position) {
                return mTabTitles.get(position);
            }

            @Override
            public void startUpdate(ViewGroup container) {}

            @Override
            public Fragment getItem(int pos) {
                Fragment f;
                switch (pos) {
                case 0:
                    f = new FirstPreferencesFragment();
                    mPageReferenceMap.put(pos, new WeakReference<Fragment>(f));
                    return f;
                case 1:
                    f = new SecondPreferencesFragment();
                    mPageReferenceMap.put(pos, new WeakReference<Fragment>(f));
                    return f;
                case 2:
                    f = new ThirdPreferencesFragment();
                    mPageReferenceMap.put(pos, new WeakReference<Fragment>(f));
                    return f;
                case 3:
                    f = new FourthPreferencesFragment();
                    mPageReferenceMap.put(pos, new WeakReference<Fragment>(f));
                    return f;
                case 4:
                    f = new FifthPreferencesFragment();
                    mPageReferenceMap.put(pos, new WeakReference<Fragment>(f));
                    return f;
                case 5:
                    f = new SixthPreferencesFragment();
                    mPageReferenceMap.put(pos, new WeakReference<Fragment>(f));
                    return f;
                case 6:
                    f = new SeventhPreferencesFragment();
                    mPageReferenceMap.put(pos, new WeakReference<Fragment>(f));
                    return f;
                default:
                    return null;
                }

            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                super.destroyItem(container, position, object);
                mPageReferenceMap.remove(position);
            }

            public Fragment getFragment(int key) {
                WeakReference<Fragment> weakReference = mPageReferenceMap.get(key);
                if (null != weakReference) {
                    return (Fragment) weakReference.get();
                }
                else {
                    return null;
                }
            }

            @Override
            public int getItemPosition(Object object) {
                if (object instanceof FirstPreferencesFragment) {
                    return 0;
                }
                else if (object instanceof SecondPreferencesFragment) {
                    return 1;
                }
                else if (object instanceof ThirdPreferencesFragment) {
                    return 2;
                }
                else if (object instanceof FourthPreferencesFragment) {
                    return 3;
                }
                else if (object instanceof FifthPreferencesFragment) {
                    return 4;
                }
                else if (object instanceof SixthPreferencesFragment) {
                    return 5;
                }
                else if (object instanceof SeventhModePreferencesFragment) {
                    return 6;
                }
                else
                    return POSITION_NONE;
            }
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.pager_layout, container, false);

            return rootView;
        }

        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            if (savedInstanceState == null) {
                //this.mPagerTitleStrip = (PagerTitleStrip) getActivity().findViewById(R.id.pager_title_strip);
                actionBar = getActivity().getActionBar();
                pager = (ViewPager) getActivity().findViewById(R.id.viewpager);


                setAdapter();
                pager.setAdapter(pageAdapter);

            }
            else {
                int index = pager.getCurrentItem();
                MyPageAdapter adapter = ((MyPageAdapter) pager.getAdapter());
                Fragment f = adapter.getFragment(index);
                getFragmentManager().beginTransaction().replace(pager.getId(), f).commit();
            }
            //Specify that tabs should be displayed in the action bar.
            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);


            pager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                @Override
                public void onPageSelected(int position) {
                    //When swiping between different app sections, select the corresponding tab.
                    //We can also use ActionBar.Tab#select() to do this if we have a reference to the tab
                    actionBar.setSelectedNavigationItem(position);
                }
            });

            //For each of the sections in the app, add a tab to the action bar.
            for (int i = 0; i < pageAdapter.getCount(); i++) {
                //Create a tab with text corresponding to the page title defined by the adapter.
                //Also specify this activity object, which implements the TabListener interface, as the listener for when this tab is selected.
                actionBar.addTab(actionBar.newTab().setText(pageAdapter.getPageTitle(i)).setTabListener(this));
            }

        }

        @Override
        public void onPause() {
            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
            super.onPause();
        }

        private void setAdapter() {
            if (pageAdapter == null)
                pageAdapter = new MyPageAdapter(getFragmentManager(), Arrays.asList(context.getResources().getStringArray(R.array.settings_titles))) {

                @Override
                public Fragment initFragment(int position) {

                    Fragment fragment;
                    if (position == 0) {
                        fragment = Fragment.instantiate(getActivity(), FirstPreferencesFragment.class.getName());

                    }
                    else if (position == 1) {
                        fragment = Fragment.instantiate(getActivity(), SecondPreferencesFragment.class.getName());
                    }
                    else if (position == 2) {
                        fragment = Fragment.instantiate(context, ThirdPreferencesFragment.class.getName());
                    }
                    else if (position == 3) {
                        fragment = Fragment.instantiate(context, FourthPreferencesFragment.class.getName());
                    }
                    else if (position == 4) {
                        fragment = Fragment.instantiate(context, FifthPreferencesFragment.class.getName());
                    }
                    else if (position == 5) {
                        fragment = Fragment.instantiate(context, SixthPreferencesFragment.class.getName());
                    }
                    else if (position == 6) {
                        fragment = Fragment.instantiate(context, SeventhPreferencesFragment.class.getName());
                    }
                    else
                        fragment = null;
                    return fragment;
                }
            };

            Handler handler = new Handler();
            handler.post(new Runnable() {
                @Override
                public void run() {

                    pager.setVisibility(View.VISIBLE);
                    //mPagerTitleStrip.setVisibility(View.VISIBLE);
                    pageAdapter.notifyDataSetChanged();
                }
            });
        }

I'm using:

android.support.v4.app.ViewPager,

android.support.v13.app.FragmentStatePagerAdapter

Upvotes: 0

Views: 1591

Answers (2)

Tunji_D
Tunji_D

Reputation: 3687

user2884639's answer above worked in my case, in other words getChildFragmentManager() is the solution to blank fragments when a new instance is created using a navigation drawer more than once.

The difference with the OP is that I'm using a FragmentPagerAdapter, not a FragmentStatePagerAdapter. My code looks like this:

Fragment hosting the ViewPager:

package com.shemanigans.mime;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.astuetz.PagerSlidingTabStrip;

public class FragmentLongTermDCA extends Fragment {
    /**
     * The fragment argument representing the section number for this
     * fragment.
     */
    private static final String ARG_SECTION_NUMBER = "section_number";
    private MyAdapter adapterViewPager;
    private ViewPager vpPager;
    private PagerSlidingTabStrip tabs;
    private OnPageChangeListener mPageChangeListener;

    private static DCAfragment dcaFrag;
    private static AnalysisFragment analysisFrag;
    private static ActivityFragment activityFrag;

    //private boolean freqSweepOn = false;

    /**
     * Returns a new instance of this fragment for the given section
     * number.
     */
    public static FragmentLongTermDCA newInstance(int sectionNumber) {
        FragmentLongTermDCA fragment = new FragmentLongTermDCA();
        Bundle args = new Bundle();
        args.putInt(ARG_SECTION_NUMBER, sectionNumber);
        fragment.setArguments(args);
        return fragment;
    }

    public FragmentLongTermDCA() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_longterm_dca, container, false);
        mPageChangeListener = new OnPageChangeListener() {
            // This method will be invoked when a new page becomes selected.
            @Override
            public void onPageSelected(int position) {
                switch(position) {
                case 0:
                    break;
                case 1:
                    /*dcaFrag.bioimpedancePlot.setVisibility(View.GONE);
                    dcaFrag.startButton.setVisibility(View.GONE);
                    dcaFrag.startButtonBar.setVisibility(View.GONE);*/
                    break;
                case 2:
                    //analysisFrag.setupFragment(freqSweepOn);
                    break;
                }
            }
            // This method will be invoked when the current page is scrolled
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                // Code goes here
            }
            // Called when the scroll state changes: 
            // SCROLL_STATE_IDLE, SCROLL_STATE_DRAGGING, SCROLL_STATE_SETTLING
            @Override
            public void onPageScrollStateChanged(int state) {
                // Code goes here
            }
        };
        InitializeViewComponents(rootView);
        return rootView;        
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        ((LongTerm) activity).onSectionAttached(
                getArguments().getInt(ARG_SECTION_NUMBER));
    }

    private void InitializeViewComponents(View rootView) {      
        vpPager = (ViewPager) rootView.findViewById(R.id.vpPager);
        tabs = (PagerSlidingTabStrip) rootView.findViewById(R.id.tabs);
        adapterViewPager = new MyAdapter(getChildFragmentManager()); // SOLTION TO PROBLEM
        vpPager.setAdapter(adapterViewPager);
        tabs.setViewPager(vpPager);
        tabs.setOnPageChangeListener(mPageChangeListener);
        tabs.setTextColor(getResources().getColor(R.color.appbasetheme_color));
        tabs.setIndicatorColor(getResources().getColor(R.color.appbasetheme_color));
        dcaFrag  = DCAfragment.newInstance(4);
        analysisFrag  = AnalysisFragment.newInstance(4);
        activityFrag  = ActivityFragment.newInstance(4);
        vpPager.setCurrentItem(1);
    }

    public static class MyAdapter extends FragmentPagerAdapter {
        private static int NUM_ITEMS = 3;

        public MyAdapter(FragmentManager fragmentManager) {
            super(fragmentManager);
        }

        // Returns total number of pages
        @Override
        public int getCount() {
            return NUM_ITEMS;
        }

        // Returns the fragment to display for that page
        @Override
        public Fragment getItem(int position) {
            switch (position) {
            case 0: // Fragment # 0 - This will show FirstFragment different title
                return activityFrag;
            case 1: // Fragment # 0 - This will show FirstFragment
                return dcaFrag;
            case 2: // Fragment # 1 - This will show SecondFragment
                return analysisFrag;
            default:
                return DCAfragment.newInstance(1);          
            }
        }

        // Returns the page title for the top indicator
        @Override
        public CharSequence getPageTitle(int position) {
            switch (position) {
            case 0: 
                return "Activity";
            case 1:
                return "Raw Data";
            case 2: 
                return "Analysis";
            default:
                return "Page " + position;
            }
        }

    }

}

OnNavigationDrawerItemSelected method inside the hosting activity that hosts the Fragment above:

@Override
public void onNavigationDrawerItemSelected(int position) {
    // update the main content by updating the fragment BioimpFragment
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    switch (position) {
    // Depending on the item selected in the list, add unique tags / identifiers.
    case 0:
        fragmentTransaction
        .replace(R.id.container, BioimpFragment.newInstance(position + 1), LIVE_DATA_TAG);          
        break;
    case 1:
        fragmentTransaction
        .replace(R.id.container, BioimpFragment.newInstance(position + 1), PAST_HOUR_TAG);          
        break;
    case 2:
        fragmentTransaction
        .replace(R.id.container, BioimpFragment.newInstance(position + 1), PAST_DAY_TAG);           
        break;
    case 3:
        fragmentTransaction
        .replace(R.id.container, FragmentLongTermDCA.newInstance(position + 1), EXPORT_DATA_TAG);           
        break;
    case 4:
        fragmentTransaction
        .replace(R.id.container, BioimpFragment.newInstance(position + 1), SCAN_TAG);           
        break;
    }
    fragmentTransaction.commit();
}

Upvotes: 0

marinko
marinko

Reputation: 55

Please try to use new MyPageAdapter(get*Child*FragmentManager()

Upvotes: 3

Related Questions