I have used the following codes for showing and canceling dialogfragment :
public static void showDialogFragment(FragmentManager fm,String type){
FragmentTransaction ft = fm.beginTransaction();
MyDialogFragment prev = (MyDialogFragment)fm.findFragmentByTag(type);
if (prev != null) {
prev.dismissAllowingStateLoss();
ft.remove(prev);
}
ft.addToBackStack(null);
MyDialogFragment newFragment = MyDialogFragment.newInstance();
try{
newFragment.show(ft,type);
}catch(IllegalStateException e){
return;
}
}
public static void cancelDialogFragment(FragmentManager fm,String tag){
FragmentTransaction ft = fm.beginTransaction();
MyDialogFragment prev = (MyDialogFragment )fm.findFragmentByTag(tag);
if (prev != null) {
prev.dismiss();
ft.remove(prev);
}
ft.addToBackStack(null);
ft.commit();
}
when I open the activity I show a dialogFragment and after receiving the data from internet I cancel it and show the recieved data, But if I press back button again it shows the dialogFragment and I have to press back button again to dismiss it and one more time to finish the activity. I know I can override onBackPressed but I want to know why this happens? why dose it again show the dialogfragment?
What is wrong with my code?
What you do is in showDialogFragment() you add this fragment to FragmentManager to backstack. Then in cancelDialogFragment() method you remove it from backstack with ft.remove(prev);
So now, your backstack is as it was before showing DialogFragment.
But what you do next is, that you add this DialogFragment again to backstack. It is not shown, but it is on the top of backstack. That means, if you press backButton, the top item in backstack, your DialogFragment, will be shown. On the next BackPress, your DialogFragment will be dismissed.
So dont add the fragment to backstack in your cancelDialogFragment() method.
Remove this line:
ft.addToBackStack(null);
Replace your entire cancelDialogFragment with this:
public static void cancelDialogFragment(FragmentManager fm,String tag){
fm.popBackStack();
}
Finally I have found the reason and the correct answer. the problem is with:
ft.addToBackStack(null);
From document:
Add this transaction to the back stack. This means that the
transaction will be remembered after it is committed, and will reverse
its operation when later popped off the stack.
Parameters name An optional name for this back stack state, or null.
that menas:
hey android I have removed dialogfragment from backstack (so there is nothing on the top of the backStack and the answer of #Vojtaaa9 is wrong because as I added the comment when you run MyDialogFragment prev = (MyDialogFragment )fm.findFragmentByTag(tag); after calling cancel you will get null, this means the backStack dose not have any dialogfragment) but remmber my action, remember that there was a dialogfragment but now it has removed. When user presses the back button the transaction reverses, it means that now there is nothing on the top of the backStack but then android pushes a dialogFragment to the backStack to do the transaction in a reverse order.
Related
So i'm having one dialog that i'm trying to show from an Activity
this activity has a navigation graph (JETPACK)
for now i can show this popup only once if i'm in my Activity
then if i close the activity and come back again to it, it's won't show the Dialog because the state of the activity is already saved. and i'm using commitAllowingStateLoss to commit this dialog fragment if i use commit it's crashing. i searched everywhere in stackoverflow couldn't find a single solution for this problem.
code of how im showing the fragment:
public void show(Context context) {
FragmentManager fragmentManager = ((AppCompatActivity) context).getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment prev = fragmentManager.findFragmentByTag(TAG_DIALOG);
if (prev != null) {
fragmentTransaction.remove(prev);
}
fragmentTransaction.add(this, TAG_DIALOG);
fragmentTransaction.commitAllowingStateLoss();
}
Please show how you open the fragment.
Do you save anything when the activity closes? I can only imagine problems with saving the actual fragment instance, but it's all guess work without seeing any code.
In an Android project, I have 3 fragments, and I navigate through them during an operation the user does.
FragmentA -> FragmentB -> FragmentC
When the user finishes the operation, I do a popBackStack to return to FragmentA
if(getFragmentManager()!=null)
if(getFragmentManager().getBackStackEntryCount()>0) {
getFragmentManager().popBackStack(getFragmentManager()
.getBackStackEntryAt(0)
.getName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
My question is:
I have an EditText, where the user writes some text, and after the call to popBackStack(), the fragment shows with the text still there.
Is there a way to know that the fragment has been popped and reset that EditText?
EDIT
This is what I use to go to next screen:
try {
String backStateName = ((Object) fragment).getClass().getName();
String fragmentTag = backStateName;
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.container, fragment, fragmentTag);
ft.setTransition(FragmentTransaction.TRANSIT_NONE);
if (addToBackStack)
ft.addToBackStack(backStateName);
ft.commit();
} catch (Exception e) {
Logging.logException(e);
}
This can be easily done using flags.
The idea is that when the popBackStack() is called, the Activity sets a flag which will be checked by FragmentA in its onResume().
Simplified steps:
When popping off FragmentC, do this:
clearEditTextOfA = true;
in onResume() of FragmentA, do this:
if (activityCallback.shouldClearEditText()) {
editText.setText("");
}
The activityCallback is an interface which lets a Fragment communicate with the Activity it is placed in. See Android Docs.
Instead of doing ft.add(), do ft.replace().
This will make the onResume() of your Fragments get called whenever they change.
Let's say I have Fragment A, from which I open a DialogFragment like this:
FragmentActivity fragmentActivity = (FragmentActivity) view.getContext();
FragmentTransaction ft = fragmentActivity.getSupportFragmentManager().beginTransaction();
Fragment prev = fragmentActivity.getSupportFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
DialogFragment fragmentDialog = MyDialogFragment.newInstance();
fragmentDialog.show(ft, "dialog");
From this Dialog, after clicking (positive / neutral / negative) button, I want to open Fragment B, which should replace Fragment A.
In the Dialog's onClick method I run a callback method of parent Activity:
#Override
public void onClick(DialogInterface dialog, int which) {
switch(which) {
case DialogInterface.BUTTON_NEUTRAL:
detailsCallbacks.openMoreDetails();
break;
}
}
And finally my Activity's openMoreDetails() method looks like this:
#Override
public void openMoreDetails() {
Fragment fragmentB = Fragment.newInstance();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, fragmentB);
ft.addToBackStack(null);
ft.commit();
}
What I get is strange. Fragment B blinks on the screen just for a fraction of a second and then is replaced (covered?) by Fragment A again.
When I click the 'up' button I get back from Fragment A, so none of these transactions were added to the back stack. I would like to show Fragment B and then, when pressing the 'up' button, go back to Fragment A.
Is it somehow possible? And what's wrong with my approach?
Just had the same problem:
Fragment A display a custom dialog fragment.
At click on one of the buttons of the dialog fragment, I wanted to remove the dialog and show Fragment B.
Fragment B was displayed and instantly disappear. My screen was displaying Fragment A again.
What was wrong on my initial implementation:
private void onClickInscription() {
FragmentInscription frag = FragmentInscription.newInstance();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.main, frag);
ft.addToBackStack(null);
ft.commit();
dismiss();
}
And the correct one:
private void onClickInscription() {
dismiss();
FragmentInscription frag = FragmentInscription.newInstance();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.main, frag);
ft.addToBackStack(null);
ft.commit();
}
So try to call dismiss first on your dialog then apply the FragmentTransction
I know this it's been a long time since the problem was posted, but I solved it by adding a if(fragmentB.getView != null) before the replace statement.
It finally doesn't do the flash and disappear thing. (:
You shouldn't be opening the dialog from FragmentA. Implement a callback from your FragmentA to your activity and let the activity handle all fragment transactions.
My app has tabs and within one tab, I have a Fragment with a ListView. When an item is clicked in the list, I try to initialize a new Fragment under that tab with the following:
private class ShowItemClickListener implements OnClickListener {
public void onClick(View v) {
Fragment showDetails = new ShowFragment();
FragmentTransaction ft = activity.getFragmentManager().beginTransaction();
ft.replace(R.id.realtabcontent, showDetails);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
ft.commit();
System.out.println(activity.getFragmentManager().getBackStackEntryCount()); // this prints 0 though
}
}
As a result, when I press the back button in Show Fragment view, it just closes the application instead of returning to the previous fragment. What am I doing wrong here?
Sorry for late answer but maybe somebody will have same question.
I was solving the same problem. It seems actual fragment is added to backstack only if this fragment isn't in current view. So it will be added to stack after when you switch to next fragment.
We add a general/normal Fragment programatically by doing something like:
fragmentTransaction.add(containerViewId, fragmentToAdd, fragmentTag);
and we replace a Fragment by another by doing something like:
fragmentTransaction.replace(containerViewId, newFragment, tagOfNewFragment);
But we add a DialogFragment by
dialogFramentInstance.show(fragmentManager, fragmentTag);
The question is that how should I replace this DialogFragment which has been added by the show() method?
dialogFramentInstance.show(fragmentManager, fragmentTag);
Just adds the dialog fragment to the fragment manger using an add transaction (with no container).
In order to replace fragments you'll need a container and since you don't have one your only option is to dismiss() the first one and show() the new one.
private void closeYourDialogFragment() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment fragmentToRemove = getSupportFragmentManager().findFragmentByTag("your_dialog_fragment");
if (fragmentToRemove != null) {
ft.remove(fragmentToRemove);
}
ft.addToBackStack(null);
ft.commit(); // or ft.commitAllowingStateLoss()
}
private void replaceYourDialogFragment() {
closeYourDialogFragment();
YourDialogFragment yourDialogFragment = new YourDialogFragment();
yourDialogFragment.show(getSupportFragmentManager(), "your_dialog_fragment");
}
Maybe you can do like this:
public void showFragment(Fragment fragment) {
if (fragment instanceof DialogFragment) {
FragmentTransaction ft = mContext.getFragmentManager().beginTransaction();
Fragment prev = mContext.getFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
Log.d(TAG, "showFragment: remove prev...." + prev.getClass().getSimpleName());
ft.remove(prev);
}
mContext.getFragmentManager().executePendingTransactions();
if (!fragment.isAdded()){
ft.addToBackStack(null);
((DialogFragment) fragment).show(ft, "dialog");
} else {
Log.w(TAG, "showFragment: fragment has been added!" );
}
}
}
So this took me a lot of digging to figure out.
Dialog fragment show method only adds fragments hence if you want to replace them you have to manually remove the previous dialog fragment.
One thing to keep in mind, it is important to use the same fragmentManager used to open the initial dialog fragment. For example if you opened the first dialog fragment via an Activity (supportFragmentManager) and now using the dialog fragment fragment manager (childFragmentManager) since they do not have the same stack you wont be able to access the original dialog fragment and remove it.