android - fragment backstack with bottomnavigationview onSaveInstanceState does not call properly

2.2k views Asked by At

I have a problem with my fragment onSaveInstanceState. I searched on stackoverflow and other sites, I could not get exactly same problem with my issue.

I have a bottom navigation view ( which is not android support library bottom navigation view if it is important ). Bottom navigation view has 4 buttons to represent 4 different fragments. Home, Search, Notifications, Profile.

enter image description here

  • launchs HomeFragment ( added to the backstack )
  • go to NotificationsFragment ( added to the backstack )
  • go to SearchFragment ( added to the backstack )
  • go to NotificationsFragment ( pops back from the backstack ) : but instance state does not saved.

here is my fragment lifecycle logs. I logged in Fragment:onSaveInstanceState() function but it did not get call, so save instance state does not call.

HomeFragment: onAttach
HomeFragment: onCreate
HomeFragment: onCreateView
HomeFragment: onViewCreated
HomeFragment: onActivityCreated
HomeFragment: onStart
HomeFragment: onResume
NotificationsFragment: onAttach
NotificationsFragment: onCreate
HomeFragment: onPause
HomeFragment: onStop
HomeFragment: onDestroyView
HomeFragment: onDestroy
HomeFragment: onDetach
NotificationsFragment: onCreateView
NotificationsFragment: onViewCreated
NotificationsFragment: onActivityCreated
NotificationsFragment: onStart
NotificationsFragment: onResume
SearchFragment: onAttach
SearchFragment: onCreate
NotificationsFragment: onPause
NotificationsFragment: onStop
NotificationsFragment: onDestroyView
NotificationsFragment: onDestroy
NotificationsFragment: onDetach
SearchFragment: onCreateView
SearchFragment: onViewCreated
SearchFragment: onActivityCreated
SearchFragment: onStart
SearchFragment: onResume
NotificationsFragment: onAttach
NotificationsFragment: onCreate
SearchFragment: onPause
SearchFragment: onStop
SearchFragment: onDestroyView
SearchFragment: onDestroy
SearchFragment: onDetach
NotificationsFragment: onCreateView
NotificationsFragment: onViewCreated
NotificationsFragment: onActivityCreated
NotificationsFragment: onStart
NotificationsFragment: onResume

MainActivity2.java

public class MainActivity2 extends BaseActivity implements FragmentManager.OnBackStackChangedListener {

    private final String TAG = getClass().getSimpleName();

    private static final String TAG_HOME = "home";
    private static final String TAG_SEARCH = "search";
    private static final String TAG_NOTIFICATIONS = "notifications";
    private static final String TAG_PROFILE = "profile";

    @BindView(R.id.btnHome) ImageView btnHome;
    @BindView(R.id.btnSearch) ImageView btnSearch;
    @BindView(R.id.btnNotifications) ImageView btnNotifications;
    @BindView(R.id.btnProfile) ImageView btnProfile;

    private FragmentManager fragmentManager;
    private ImageView selectedImageButton;

    public MainActivity2() {
        setTAG(TAG);
    }

    @Override
    public void onBackPressed() {
        int entryCount = fragmentManager.getBackStackEntryCount();

        // if first fragment is not on screen, just pop back to the previous fragment.
        if (entryCount > 1) {
            fragmentManager.popBackStack();
            return;
        }

        // if first fragment is showing, then finish the activity.
        finish();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);

        ButterKnife.bind(this);

        fragmentManager = getSupportFragmentManager();

        onHome();

        fragmentManager.addOnBackStackChangedListener(this);
    }

    @Override
    public void onBackStackChanged() {
        Log.v(TAG, "entryCount : " + fragmentManager.getBackStackEntryCount());
        Fragment fragment = fragmentManager.findFragmentById(R.id.container);
        String tag = null;
        if (fragment instanceof HomeFragment) {
            tag = TAG_HOME;
        } else if (fragment instanceof SearchFragment) {
            tag = TAG_SEARCH;
        } else if (fragment instanceof NotificationsFragment) {
            tag = TAG_NOTIFICATIONS;
        } else if (fragment instanceof ProfileFragment) {
            tag = TAG_PROFILE;
        }

        handleTitle(tag);
    }

    private void handleTitle(String tag) {
        switch (tag) {
            case TAG_HOME:
                setTitle("Home");
                break;
            case TAG_SEARCH:
                setTitle("Search");
                break;
            case TAG_NOTIFICATIONS:
                setTitle("Notifications");
                break;
            case TAG_PROFILE:
                setTitle("Profile");
                break;
        }
    }

    private void changeFragment(Fragment fragment, String tag, boolean addBackStack) {
        KeyboardUtils.hideKeyboard(this);

        Fragment existFragment = fragmentManager.findFragmentByTag(tag);

        if (existFragment == null) {
            // fragment not in back stack, create it.
            FragmentTransaction ft = fragmentManager.beginTransaction();
            ft.replace(R.id.container, fragment, tag);
            if (addBackStack)
                ft.addToBackStack(tag);
            ft.commit();
            Log.w(TAG, tag + " added to the backstack");
        } else {
            // fragment in back stack, call it back.
            FragmentTransaction ft = fragmentManager.beginTransaction();
            ft.replace(R.id.container, existFragment, tag);
            ft.commit();
            Log.w(TAG, tag + " fragment returned back from backstack");
        }
    }

    private void onBottomBarViewSelected(Fragment fragment, String tag, ImageView btnSelected, boolean addToBackStack) {
        // this control will avoid re-selected same fragment.
        if (selectedImageButton == btnSelected)
            return;

        changeFragment(fragment, tag, addToBackStack);
        selectedImageButton = btnSelected;
    }

    @OnClick(R.id.btnHome)
    public void onHome() {
        onBottomBarViewSelected(HomeFragment.newInstance(), TAG_HOME, btnHome, true);
    }

    @OnClick(R.id.btnSearch)
    public void onSearch() {
        onBottomBarViewSelected(SearchFragment.newInstance(), TAG_SEARCH, btnSearch, true);
    }

    @OnClick(R.id.btnNotifications)
    public void onNotifications() {
        onBottomBarViewSelected(NotificationsFragment.newInstance(), TAG_NOTIFICATIONS, btnNotifications, true);
    }

    @OnClick(R.id.btnProfile)
    public void onProfile() {
        onBottomBarViewSelected(ProfileFragment.newInstance(), TAG_PROFILE, btnProfile, true);
    }
}

one of the example fragment for BottomNavigationView fragments

NotificationsFragment.java

public class NotificationsFragment extends BaseFragment implements NotificationsView,
        NotificationsAdapter.NotificationsListener {

    private final String TAG = getClass().getSimpleName();

    @BindView(R.id.recyclerView) RecyclerView recyclerView;
    @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout;
    @BindView(R.id.txtEmpty) TextView txtEmpty;

    private NotificationsPresenter presenter;
    private NotificationsAdapter adapter;

    public static NotificationsFragment newInstance() {
        NotificationsFragment fragment = new NotificationsFragment();
        Bundle args = new Bundle();
        // put args
        fragment.setArguments(args);
        return fragment;
    }

    public NotificationsFragment() {
        setTAG(TAG);
        setHasOptionsMenu(false);
        setRetainInstance(false);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initArguments();
        initVariables();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        View rootView = inflater.inflate(R.layout.notifications_fragment, container, false);
        ButterKnife.bind(this, rootView);
        initializeLayout();
        presenter.attachView(this);
        return rootView;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        fetchNotifications();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        Log.wtf(TAG, "onSaveInstanceState");
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onDestroy() {
        presenter.destroy();
        super.onDestroy();
    }

    private void fetchNotifications() {
        presenter.fetchNotifications();
    }

    @Override
    protected void initializeLayout() {
        swipeRefreshLayout.setOnRefreshListener(this::fetchNotifications);
        swipeRefreshLayout.setColorSchemeResources(R.color.colorSwipeProgress);

        recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));

        recyclerView.addItemDecoration(new DividerItemDecoration(getContext()));

        recyclerView.setAdapter(adapter);

        ((SimpleItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
    }

    @Override
    protected void initVariables() {
        presenter = new NotificationsPresenter();
        adapter = new NotificationsAdapter(this);
    }

    @Override
    protected void initArguments() {
        // init arguments
    }
}

EDIT I just added the home screen image.

0

There are 0 answers