my activity use fragment what is pre initialized(initializing onCreate)
when fragment (A) will show first, using FragmentTransaction.add(A). If fragment B request show(if it's first), FragmentTransaction.detach(A) and FragmentTransaction.add(B).
fragment A is request show again, use FragmentTransaction.detach(B) and FragmentTransaction.attach(A).
this action is in BottomNavagationView.OnNavigationItemSelectedListener.
in this situation, i make app finished(use back button, but not use activity.finish), and run that app again, don't showing any fragment(expect fragment B is show).
and, when i click BottomNavagationView Button(fragment add),
cause java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at commit().
how to solve this problem?
commitallowingstateloss() seems to not working right...
attach my code:
public class TestActivity extends AppCompatActivity {
private TextView mTextMessage;
private BottomNavigationView navigation;
private Fragment homeFragment = null;
private Fragment seatFragment = null;
private Fragment settingFragment = null;
private Fragment dialogFragment = null;
private FragmentUtil fUtil = null;
private boolean finishFlag = false;
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
fUtil.addOnMain(R.id.content, homeFragment, "home", FragmentTransaction.TRANSIT_FRAGMENT_FADE);
return true;
case R.id.navigation_seat:
fUtil.addOnMain(R.id.content, seatFragment, "seat", FragmentTransaction.TRANSIT_FRAGMENT_FADE);
return true;
case R.id.navigation_shelf:
return true;
case R.id.navigation_settings:
fUtil.addOnMain(R.id.content, settingFragment, "setting", FragmentTransaction.TRANSIT_FRAGMENT_FADE);
return true;
}
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
// mTextMessage = (TextView) findViewById(R.id.message);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
BottomNavigationViewHelper.disableShiftMode(navigation);
fUtil = FragmentUtil.getInstance(this);
homeFragment = new HomeFragment();
seatFragment = new SeatMenuFragment();
settingFragment = new SettingFragment();
dialogFragment = new DialogFragment();
findViewById(R.id.login_popup).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(fUtil.isContained(dialogFragment)) {
return;
} else {
fUtil.add(R.id.content, dialogFragment, "", FragmentTransaction.TRANSIT_FRAGMENT_FADE);
}
}
});
}
and, FragmentUtil :
public class FragmentUtil {
private Context context = null;
private FragmentManager manager = null;
private static FragmentUtil sInstance = null;
private Fragment currentFragment = null;
public static FragmentUtil getInstance(FragmentActivity activity) {
if (sInstance == null) {
sInstance = new FragmentUtil(activity);
}
return sInstance;
}
private FragmentUtil(FragmentActivity activity) {
this.context = activity.getApplicationContext();
this.manager = activity.getSupportFragmentManager();
}
public FragmentManager getManager() {
return manager;
}
private void setTransition(FragmentTransaction ft, int transition) {
ft.setTransition(transition);
}
public void attach(Fragment fragment) {
if(fragment.isDetached()) {
FragmentTransaction ft = manager.beginTransaction();
ft.attach(fragment);
ft.commit();
currentFragment = fragment;
} else {
return;
}
}
public void attach(Fragment fragment, int transition) {
if(fragment.isDetached()) {
FragmentTransaction ft = manager.beginTransaction();
ft.attach(fragment);
if (transition != FragmentTransaction.TRANSIT_UNSET) {
setTransition(ft, transition);
}
ft.commit();
currentFragment = fragment;
} else {
return;
}
}
public void detach(Fragment fragment, int transition) {
if(fragment.isDetached()) {
return;
} else {
FragmentTransaction ft = manager.beginTransaction();
ft.detach(fragment);
if(transition != FragmentTransaction.TRANSIT_UNSET) {
setTransition(ft, transition);
}
currentFragment = null;
ft.commit();
}
}
public void detach(Fragment fragment) {
if(fragment.isDetached()) {
return;
} else {
FragmentTransaction ft = manager.beginTransaction();
ft.detach(fragment);
ft.commit();
currentFragment = null;
}
}
public void add(int resId, Fragment fragment, String tag) {
//manager.executePendingTransactions();
if(fragment.isAdded()) {
return;
} else {
FragmentTransaction ft = manager.beginTransaction();
ft.addToBackStack(null);
ft.add(resId, fragment, tag);
ft.commit();
currentFragment = fragment;
}
}
public void addOnMain(int resId, Fragment fragment, String tag) {
//manager.executePendingTransactions();
if(fragment.isAdded()) {
return;
} else {
manager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
FragmentTransaction ft = manager.beginTransaction();
ft.add(resId, fragment, tag);
ft.commit();
currentFragment = fragment;
}
}
public void remove(Fragment fragment) {
//manager.executePendingTransactions();
manager.popBackStack();
FragmentTransaction ft = manager.beginTransaction();
ft.remove(fragment);
ft.commit();
}
public void add(int resId, Fragment fragment, String tag, int transition) {
//manager.executePendingTransactions();
if(fragment.isAdded()) {
return;
} else {
FragmentTransaction ft = manager.beginTransaction();
ft.addToBackStack(null);
ft.add(resId, fragment, tag);
setTransition(ft, transition);
ft.commit();
currentFragment = fragment;
}
}
public void addOnMain(int resId, Fragment fragment, String tag, int transition) {
//manager.executePendingTransactions();
if(fragment.isAdded()) {
return;
} else {
manager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
FragmentTransaction ft = manager.beginTransaction();
ft.add(resId, fragment, tag);
setTransition(ft, transition);
ft.commit();
currentFragment = fragment;
}
}
public void remove(Fragment fragment, int transition) {
//manager.executePendingTransactions();
FragmentTransaction ft = manager.beginTransaction();
ft.remove(fragment);
setTransition(ft, transition);
ft.commit();
}
HomeFragment and others do not anything. just inflate xml.
I happen to be working on a project with a BottomNavigationView and Fragments as well at the moment. Basically this is how I do things (left some of the code out for simplicity).
MainActivity.java:
public class MainActivity extends AppCompatActivity
implements OnFragmentSelectedListener {
// the MainFragment in Fragment container with id R.id.fragment_container_main and state "started"
private MainFragment selectedFragment;
// MainFragments
private HomeFragment homeFragment;
private SeatFragment seatFragment;
private SettingFragment settingFragment;
private DialogFragment dialogFragment;
private BottomNavigationView navBar;
private BottomNavigationView.OnNavigationItemSelectedListener onNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
/*
* Navigation strategy:
* - if the Fragment being selected on the NavBar is already visible, ignore the click
* - else navigate to the requested Fragment, creating it if necessary.
*/
switch (item.getItemId()) {
case R.id.navigation_home:
if (!(selectedFragment instanceof HomeFragment)) {
if (homeFragment == null) {
homeFragment = new HomeFragment();
}
displayFragment(homeFragment, R.id.fragment_container_main);
}
return true;
case R.id.navigation_seat:
if (!(selectedFragment instanceof SeatFragment)) {
if (seatFragment == null) {
seatFragment = new SeatFragment();
}
displayFragment(seatFragment, R.id.fragment_container_main);
}
return true;
case R.id.navigation_setting:
if (!(selectedFragment instanceof SettingFragment)) {
if (settingFragment == null) {
settingFragment = new SettingFragment();
}
displayFragment(settingFragment, R.id.fragment_container_main);
}
return true;
case R.id.navigation_dialog:
if (!(selectedFragment instanceof DialogFragment)) {
if (dialogFragment == null) {
dialogFragment = new DialogFragment();
}
displayFragment(dialogFragment, R.id.fragment_container_main);
}
return true;
}
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
navBar = findViewById(R.id.navigation);
navBar.setOnNavigationItemSelectedListener(onNavigationItemSelectedListener);
if (savedInstanceState == null) {
homeFragment = new HomeFragment();
displayFragment(homeFragment, R.id.fragment_container_main);
}
}
/**
* Replaces the fragment (MainFragment) in main fragment container with fragmentToDisplay, adding
* the transaction to the back stack.
*
* @param fragmentToDisplay the fragment to display
*/
@Override
public void displayFragment(MainFragment fragmentToDisplay, int fragmentContainerId) {
FragmentManager fm = getSupportFragmentManager();
ft = fm.beginTransaction();
ft.replace(fragmentContainerId, fragmentToDisplay, fragmentToDisplay.getClass().getName());
ft.addToBackStack(null);
ft.commit();
}
@Override
public void onBackPressed() {
if (selectedFragment == null || !selectedFragment.onBackPressed()) {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStackImmediate();
} else {
super.onBackPressed();
}
}
}
@Override
public void setSelectedFragment(MainFragment fragment) {
selectedFragment = fragment;
}
}
MainFragment.java:
/**
* Abstract Fragment class for MainActivity Fragments
* <p>
* Created by kazume on 01.02.2018.
*/
public abstract class MainFragment extends Fragment {
protected OnFragmentSelectedListener onFragmentSelectedListener;
/**
* Called when a back-press occurs in MainActivity popping the back stack (or exiting the app if
* the back stack is empty ) by default. The return boolean offers the possibility to let the
* MainFragment consume the back-press and stay on the MainFragment by returning true.
*
* @return Returns true if MainActivity's back-press is consumed by MainFragment and false if
* back-press is handled by MainActivity
*/
@SuppressWarnings("SameReturnValue")
public boolean onBackPressed() {
return false;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
onFragmentSelectedListener = (OnFragmentSelectedListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement OnFragmentSelectedListener");
}
}
@Override
public void onStart() {
super.onStart();
if (this.getId() == R.id.fragment_container_main) {
onFragmentSelectedListener.setSelectedFragment(this);
}
}
@Override
public void onDetach() {
super.onDetach();
onFragmentSelectedListener = null;
}
}
OnFragmentSelectedListener.java
/**
* Interface to be implemented by an Activity hosting MainFragments. Via this interface, the hosting
* activity always has a reference to the Fragment currently being displayed (state "started") in the
* main fragment container.
*
* Created by kazume on 05.02.2017.
*/
public interface OnFragmentSelectedListener {
void setSelectedFragment(MainFragment fragment);
}