Android childfragments from viewpager getActivity returns null

I have activity, and using the button I switch between two fragments (MAIN and SETTINGS). In the MAIN fragment, I have a ViewPager with 4 child fragments.

At first, everything works fine, but if I rotate the screen, the getActivity() fragments for the fragments in the ViewPager return zero.

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

Fragmentmentmain

  @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 everything works fine, but after turning the screen I get null for getActivity(); in 4 child fragments: search, favorites, home and room.

Debug Logcat

1 launch:

 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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 changing the screen orientation:

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

+5
source share
2 answers

After several hours of debugging, I realized that if you have only one fragment (without child or nested fragments) attached to your activity, you do not need to re-add the 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 do not need to re-attach the fragment, the Android system will do it for you.

And the solution for getting NPE in getActivity(); in child fragments:

Use the FragmentStatePagerAdapter for your ViewPager adapter.

and override the saved state method:

 @Override public Parcelable saveState() { return null; } 

I do not know why, but setRetainInstance(false); it didn’t help me, and I think that it will remain a mystery to me.

+2
source

It is good practice to follow a pattern like this when working with fragments:

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); view = view.findViewById(R.id.view); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // do your thing here populateViewPager(); } 

1) Use OnCreateView to set the fragment view, 2) OnViewCreated to initialize the view, and 3) OnActivityCreated to set things up.

Using getActivity() inside OnActivityCreated ensures that getActivity() does not return null. This method is called only after the operation is fully initialized. OnAttach , OnCreate , OnCreateView may appear even before the activity is created.

0
source

Source: https://habr.com/ru/post/1205939/


All Articles