I have an activity and with a button I am switching between the two fragments (MAIN & SETTINGS). In the MAIN fragment I have a ViewPager
with 4 child fragments.
At first run everything works fine, but if I rotate the screen, the getActivity()
for fragments within the ViewPager
is returning null.
ActivityMain:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Add or show the fragments
showHideScreenFragment(FRAGMENT_MAIN);
}
private void showHideScreenFragment(String tag) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
// Get the fragment from the backstack if it is existing
BaseFragment oldFragment = getFragmentFromBackstack(tag);
// Get the current fragment from the layout
BaseFragment currentFragment = getCurrentFragment();
if (oldFragment == null) {
if (currentFragment != null) {
ft.hide(currentFragment);
}
ft.add(getMainContainerId(), getFragmentInstance(tag), tag);
}
else {
if (currentFragment != null) {
if (isSameFragment(oldFragment, currentFragment))
return;
ft.hide(currentFragment);
}
if (oldFragment.isHidden())
ft.show(oldFragment);
}
ft.commit();
fm.executePendingTransactions();
}
private BaseFragment getFragmentInstance(String tag) {
if (tag.equals(FRAGMENT_MAIN)) return getFragmentMain();
if (tag.equals(FRAGMENT_SETTINGS)) return getFragmentSettings();
throw new RuntimeException("Fragment not found !");
}
private FragmentMain getFragmentMain() {
return new FragmentMain();
}
private FragmentSettings getFragmentSettings() {
return new FragmentSettings();
}
private BaseFragment getFragmentFromBackstack(String tag) {
if (tag.equals(FRAGMENT_MAIN)) return getFragmentMainFromBackstack();
if (tag.equals(FRAGMENT_SETTINGS)) return getFragmentSettingsFromBackstack();
throw new RuntimeException("Fragment not found !");
}
private FragmentMain getFragmentMainFromBackstack() {
return (FragmentMain) getSupportFragmentManager().findFragmentByTag(FRAGMENT_MAIN);
}
private FragmentSettings getFragmentSettingsFromBackstack() {
return (FragmentSettings) getSupportFragmentManager().findFragmentByTag(FRAGMENT_SETTINGS);
}
private boolean isSameFragment(Fragment f1, Fragment f2) {
return f1.getTag().equals(f2.getTag());
}
FragmentMain:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
viewPager = (ViewPager) view.findViewById(R.id.viewPager);
// Add the 4 child fragments to the viewpager
populateViewPager();
// Debugging
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
_printFragmentStates();
}
}, 2500);
return view;
}
private void populateViewPager() {
ArrayList<BaseMainFragment> fragments = new ArrayList<BaseMainFragment>();
fragments.add(new FragmentSearch());
fragments.add(new FragmentFavorites());
fragments.add(new FragmentHouse());
fragments.add(new FragmentRoom());
adapterMain = new AdapterMain(getChildFragmentManager(), fragments);
viewPager.setOffscreenPageLimit(4);
viewPager.setAdapter(adapterMain);
}
// DEBUGGING
private void _printFragmentStates() {
Activity actSearch = null;
Activity actFav = null;
Activity actHouse = null;
Activity actRoom = null;
actSearch = getFragmentSearch().getActivity();
actFav = getFragmentFavorites().getActivity();
actHouse = getFragmentHouse().getActivity();
actRoom = getFragmentRoom().getActivity();
Functions.logd("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
Functions.logd("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
Functions.logd("Main fragment act, is null: " + (getActivity() == null));
Functions.logd("Search act, is null: " + (actSearch == null));
Functions.logd("Favorite act, is null: " + (actFav == null));
Functions.logd("House act, is null: " + (actHouse == null));
Functions.logd("Room act, is null: " + (actRoom == null));
Functions.logd("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
Functions.logd("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
private FragmentSearch getFragmentSearch() {
return (FragmentSearch) adapterMain.getItem(0);
}
private FragmentFavorite getFragmentFavorite() {
return (FragmentFavorite) adapterMain.getItem(1);
}
private FragmentHouse getFragmentHouse() {
return (FragmentHouse) adapterMain.getItem(2);
}
private FragmentRoom getFragmentHouse() {
return (FragmentRoom) adapterMain.getItem(3);
}
As I said, at first run everything works fine, but after I rotate the screen, I am getting null for getActivity();
in the 4 child fragments: Search, Favorite, House and Room.
1 run:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Main fragment act, is null: false
Search act, is null: false
Favorite act, is null: false
House act, is null: false
Room act, is null: false
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After screen orientation changed:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Main fragment act, is null: false
Search act, is null: true
Favorite act, is null: true
House act, is null: true
Room act, is null: true
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
What am I doing wrong?
After hours of debugging, I figured out that if you're having only 1 fragment (without child or nested fragments) attached to your activity, then you don't need to re-add your fragment.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Add or show the fragments if the savedInstance is null, otherwise let the system reattach your fragment.
if (savedIstance == null)
showHideScreenFragment(FRAGMENT_MAIN);
}
You don't need to reattach the fragment, the android system will do this for you.
And the solution for getting NPE
at getActivity();
in child fragments is:
Use FragmentStatePagerAdapter
for your ViewPager
's adapter.
and override the saved state method:
@Override
public Parcelable saveState() {
return null;
}
I don't know why, but setRetainInstance(false);
does not helped me, and I think this will remain a mystery for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With