I am trying to set up a dialog fragment that pops up when my android user receives a push notification. The code I have below triggers the dialog. The issue I am running into is that if my users get multiple pushes, they will see multiple dialog boxes popup.
My desired action is to show only one dialog box and if another one pops up before the current one is closed, the current one should be destroyed and then the new one shown.
public abstract class BaseActivity extends ActionBarActivity {
public void showShiftsDialog(String time) {
String DIALOG_ALERT = "dialog_alert";
FragmentTransaction transaction = getFragmentManager().beginTransaction();
android.app.Fragment prev = getFragmentManager().findFragmentByTag(DIALOG_ALERT);
if (prev != null) transaction.remove(prev);
transaction.addToBackStack(null);
// create and show the dialog
DialogFragment newFragment = ShiftsDialogFragment.newInstance(time);
newFragment.show(getSupportFragmentManager().beginTransaction(), DIALOG_ALERT);
}
}
I have tried using the code from the android docs (http://developer.android.com/reference/android/app/DialogFragment.html). When debugging, it looks like prev is always null.
From my understanding, it looks like I am attaching the DialogFragment to the SupportFragmentManager:
newFragment.show(getSupportFragmentManager().beginTransaction(), DIALOG_ALERT);
and when I try to check to see if there are any current DialogFragment, I am checking from the FragmentManager:
android.app.Fragment prev = getFragmentManager().findFragmentByTag(DIALOG_ALERT);
If I try to change the code to try to get it from the SupportFragmentManager, I get an incompatible type error where it is expecting android.app.Fragment, but I am returning a android.support.v4.app.Fragment:
android.app.Fragment prev = getSupportFragmentManager().findFragmentByTag(DIALOG_ALERT);
How can I manage my DialogFragment so that only one is shown at any given time?
Working Solution
public void showShiftsDialog(String time) {
String DIALOG_ALERT = "dialog_alert";
android.support.v4.app.FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
android.support.v4.app.Fragment prev = getSupportFragmentManager().findFragmentByTag(DIALOG_ALERT);
if (prev != null){
DialogFragment df = (DialogFragment) prev;
df.dismiss();
transaction.remove(prev);
}
transaction.addToBackStack(null);
// create and show the dialog
DialogFragment newFragment = ShiftsDialogFragment.newInstance(time);
newFragment.show(getSupportFragmentManager().beginTransaction(), DIALOG_ALERT);
}
Your issue seems to be the incompatibility of the DialogFragment. If ShiftsDialogFragment is a sub-class of android.support.v4.app.DialogFragment you can use
android.support.v4.app.Fragment prev = getSupportFragmentManager().findFragmentByTag(DIALOG_ALERT);
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.
I'm trying to update a DialogFragment display at runtime, setting the visibility of a view to VISIBLE or GONE depending on some conditions.
Basically, I inflate my layout in the DialogFragment, show a progress bar while I do some background request, and update the DialogFragment layout depending of the result of my request.
Sometimes it works, sometimes it doesn't update my UI accordingly, even if the logs show that the method is invoked and the thread is the Main thread.
Any idea why ?
In DialogFragment
#Override
public void showData(List<MyDataViewModel> data) {
Timber.d("Fragment Show data " + (Looper.myLooper() == Looper.getMainLooper()));
Timber.d("Fragment Show data " + this);
Timber.d("Fragment Show data " + data.size());
if (mConnectedContainer.getVisibility() != View.VISIBLE) {
mConnectedContainer.setVisibility(View.VISIBLE);
}
}
In Activity
#Override
public void showDialog() {
// DialogFragment.show() will take care of adding the fragment
// in a transaction. We also want to remove any currently showing
// dialog, so make our own transaction and take care of that here.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
// Create and show the dialog.
DialogFragment newFragment = MyDialogFragment.newInstance();
newFragment.show(ft, "dialog");
}
Also tried this way
#Override
public void showDialog() {
// Create and show the dialog.
DialogFragment newFragment = MyDialogFragment.newInstance();
newFragment.show(getSupportFragmentManager(), "dialog");
}
After some investigation, the issue was linked to my use of RxJava.
I was executing a first UseCase, and in the onNext, executing another one.
I split my code in two different dialogs to make it simpler, and have only one use case updating the UI, and no more issue.
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.
I have an application that is using fragments. The set up is like so:
Main Activity loads, loads fragment activity into right portion of parent activity
-From the Fragment, I launch a DialogFragment which displays a list of users
-From the DialogFragment, if you click on one of the users in the list, it hides the list of users DialogFragment .hide() and shows a new DialogFragment containing the details about the user
This all works great. However, when I click the Close button on the Details DialogFragment, I'd like to dismiss() that dialog, and re-show the List of Users dialog.
I realize this is somewhat difficult to follow.
Does anyone have any insight that may help me?
UPDATE
The code I use to display the DialogFragment is the following:
MyDialogFragment dialog = new MyDialogFragment();
dialog.show(getFragmentManager(), "MyDialogFragment");
Then once in the dialog fragment, if I wanted to hide it and show the details fragment I call
dialog.hide();
MyDetailsFragment details = new MyDetailsFragment();
details.show(getFragmentManager(), "MyDetailsFragment");
Basically I need to be able to re-show the dialog above when I dismiss the details.
When a fragment transaction is performed, you can add it to the back stack which can be reversed on dismissing the dialog.
Begin a fragment transaction and use the DialogFragment.show(FragmentTransaction transaction, String tag) variant which takes the FragmentTransaction as parameter. It will take care of showing the Dialog, adding the fragment to the passed transaction and then committing the transaction. Later when the Dialog is dismissed, DialogFragment will itself take care of popping the transaction.
You can follow the first sample posted in the DialogFragment docs.
Here is the working code:
public void launchMyDialog(View v) {
// DialogFragment.show() will take care of adding the fragment
// in a transaction. We also want to remove any currently showing
// dialog, so make our own transaction and take care of that here.
FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag("mydialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
MyDialogFragment dialog = new MyDialogFragment();
dialog.show(ft, "mydialog");
}
public static class MyDialogFragment extends DialogFragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_main, container, false);
Button b = (Button) v.findViewById(R.id.button);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag("mydialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
MyDetailsFragment dialog = new MyDetailsFragment();
dialog.show(ft, "mydialog");
}
});
return v;
}
}
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.