Reputation: 1
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
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