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.
- 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.