I have an Activity with an EditText
and a Button
. As soon as there is a number entered in the EditText and the Button is clicked, a Fragment (that covers up the whole screen) is being shown for two seconds, and then removed. Both Transactions have showCustomAnimations()
called. In code, after I call commit()
on the remove FragmentTransaction, the soft keyboard is shown via showSoftInput()
.
The problem I face: While the remove animation is running and the Fragment already slid out of the screen by 80%, the softkeyboard pops up. Now if you quickly enter a number and press the button, the app crashes, because the previous animation still was running.
I already saw several answers, but I found them to not be sufficient or working. Any call for commitNow()
or executePendingTransitions()
doesn't help, as the Transaction is committed, the problem is, that the animation is still running afterwards. The method getVisibleUserHint()
to check whether an Activity is visible is deprecated.
Code:
TrueFragment trueFragment = new TrueFragment();
fabNext.setOnClickListener(new View.OnClickListener() { //fabNext is my button
@Override
public void onClick(View v) {
fabNext.setEnabled(false); //blocking button to avoid clicking (... further code for this...)
inputManager.hideSoftInputFromWindow(constraintLayoutCalculating.getWindowToken(), 0); //hide Keyboard
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); //FragmentTransaction to show the Fragment
transaction.setCustomAnimations(R.animator.slide_in, 0);
transaction.add(R.id.constraintLayoutCalculating, trueFragment);
transaction.commitAllowingStateLoss();
getSupportFragmentManager().executePendingTransactions();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
FragmentTransaction transaction2 = getSupportFragmentManager().beginTransaction(); //FragmentTransaction to remove the Fragment
transaction2.setCustomAnimations(0, R.animator.slide_out);
transaction2.remove(trueFragment);
transaction2.commitAllowingStateLoss();
editText.setText(null); //reset EditText
editText.requestFocus();
textInputLayout.setError(null);
inputManager.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); //show Keyboard
fabNext.setEnabled(true); //reenable button at the end - Problem: Button made clickable again, even if the remove FragmentTransaction animation hasn't finished
}
}, 1000);
}
This is the crash I am getting. A search on StackOverflow showed me that it has to do with starting a FragmentTransaction while another still isn't finished.
--------- beginning of crash
2020-02-17 10:27:29.787 23467-23467/my.top.secretpreciousname E/AndroidRuntime: FATAL EXCEPTION: main
my.top.secretpreciousname, PID: 23467
java.lang.IllegalStateException: Restarter must be created only during owner's initialization stage
at androidx.savedstate.SavedStateRegistryController.performRestore(SavedStateRegistryController.java:58)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2585)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:838)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
at androidx.fragment.app.FragmentManagerImpl.executePendingTransactions(FragmentManagerImpl.java:183)
at my.top.secretpreciousname.CalculatingActivity$1.onClick(CalculatingActivity.java:254)
at android.view.View.performClick(View.java:7339)
at my.top.secretpreciousname.CalculatingActivity$2.onEditorAction(CalculatingActivity.java:320)
at android.widget.TextView.doKeyDown(TextView.java:8617)
at android.widget.TextView.onKeyDown(TextView.java:8486)
at android.view.KeyEvent.dispatch(KeyEvent.java:3359)
at android.view.View.dispatchKeyEvent(View.java:13312)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1912)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1912)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1912)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1912)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1912)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1912)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1912)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1912)
Is there nice solution for this? Thanks in advance for any help.
It turns out that I have to add the line
transaction2.addToBackStack(null);
to the animated FragmentTransaction to achieve that it won't crash when a new Transaction is triggered before the previous one has finished its animation. Still not sure if this can be considered as a valid solution, as actually I don't want backstack functionality with these Fragments, so I have to temporarily block the back button or flush the Backstack after every Transaction.