DialogFragment shows only once - - android

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.

Related

fragment transaction - pop backstack and then add fragment

I am trying to do the following use case in Android Fragments. I have 2 fragments.
Fragment A -> Fragment B
When a user does something in Fragment B, I want to have the back stack as follows
Fragment A -> Fragment C. So, when the user presses back I want the user to go back to Fragment A.
I have tried the following
mFragmentManager.popBackStackImmediate();
FragmentTransaction fragmentTransaction = fMgr.beginTransaction()
.replace(R.id.base, Fragment_C, "1")
.addToBackStack(null)
.commitAllowingStateLoss();
The problem here is that I can see Fragment A for a short period of time before Fragment C is shown
If I do the following
mFragmentManager.popBackStackImmediate();
FragmentTransaction fragmentTransaction = fMgr.beginTransaction()
.replace(R.id.base, Fragment_C, "1")
.addToBackStack(null)
.commitNowAllowingStateLoss();
I get the error
This transaction is already being added to the back stack
I can get Fragment C to show up if I do this BUT
mFragmentManager.popBackStackImmediate();
FragmentTransaction fragmentTransaction = fMgr.beginTransaction()
.replace(R.id.base, Fragment_C, "1")
.commitNowAllowingStateLoss();
This works and I don't see Fragment A and see Fragment C but the back button takes the user out of the application. So, is it possible that we can pop the back stack of the fragment and then add another fragment to the back stack w/o showing Fragment A AND the back button takes the user back to Fragment A
Here is an easy method to add fragments to fragments or to adapters within fragments...
from your base activity, make your fragment manager static. assume this activity is called dashboard.
static FragmentManager support;
Don't forget to initialize this in onCreate.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_dashboard);
support = getSupportFragmentManager();
define your new fragment inside your adapter or fragment.
users_item_fragment dialog = new users_item_fragment();
//also, let's add some data...
Bundle args = new Bundle();
args.putString("device", devicesList.get(position));
use the following method to add the fragment easily wherever you would like
//pick an easily remembered tag
public void replace(Fragment fragment, String tag){
FragmentManager man = dashboard.support;
FragmentTransaction fragt = man.beginTransaction();
if(!fragment.isAdded()) {
dashboard.lastTag = dashboard.fragtag;//not needed, but helpful w/ backpresses
fragt.add(R.id.fragment_container, fragment, tag)
.hide(man.findFragmentByTag(fragtag)).commit();
dashboard.fragtag = dashboard.tag;//not needed, but helpful w/ backpresses
}
if(fragment.isAdded() && fragment.isHidden()) {
dashboard.lastTag = dashboard.fragtag;//not needed, but helpful w/ backpresses
fragt.show(fragment);
fragt.hide(man.findFragmentByTag(fragtag)).commit();
dashboard.fragtag = dashboard.tag;//not needed, but helpful w/ backpresses
}
}
To implement this with backpresses working correctly, add this in you onBackPress method of your main activity:
#Override
public void onBackPressed() {
FragmentManager man = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = man.beginTransaction();
fragmentTransaction.hide(getSupportFragmentManager().findFragmentByTag(fragtag))
.show(getSupportFragmentManager().findFragmentByTag(lastTag)).commit();
fragtag = lastTag;// holds the last fragment
}
}
It's easy to see the logic here and easy to manipulate back press events using this.

Android reload fragments stack on restore

I’m developing an android application that makes heavy use of fragments, I’m running into an issue and I’ve been unable to find a solution so far.
The flow is this: the app is launched and MainActivity is the first responder, now, depending on user interaction several fragments gets loaded and pushed onto the stack.
Here is an example:
Main Activity -> fragment A -> fragment B -> fragment C -> etc..
Back history is enabled like so:
fragment C -> fragment B -> fragment A -> etc..
Everything works perfectly fine as long as my application is in foreground but everything breaks when the application goes in background.
If I’m on fragment B for example and I press the home button the application goes in background and when I restore it back it starts from MainActivity with fragment A.
Also, the toolbar shows the title of fragment B and, since fragment A contains a recyclerview I can see parts of fragment B between item rows, like a background image.
This is how I load fragments:
public void loadFragment(Fragment fragment, Boolean addToStack) {
// Load fragment
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_container, fragment);
fragmentTransaction.addToBackStack(null);
// show back button
if (addToStack) {
// Code to show the back button.
}
else if (fragmentManager.getBackStackEntryCount() > 0 && !addToStack) {
hideBackButton();
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
fragmentTransaction.commitAllowingStateLoss();
}
I call this function from MainActivity and from the fragments:
MyFragment theFragment = new MyFragment();
MainActivity.instance.loadFragment(theFragment, true);
What I want to achieve is that when the application is restored it gets straight to the previously loaded fragment, keeping the entire "back" history. How can I do this?
I'm not sure if other portions of code are needed, but if so I'll post them as required.
call the onResume() function:
public void onResume(){
Fragment frg = null;
frg = getSupportFragmentManager().findFragmentByTag("Your_Fragment_TAG");
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.detach(frg);
ft.attach(frg);
ft.commit();
}
Ok so, after a lot of research I found the issue… and the issue was a mistake of mine.
I’d like to report it here for everyone that might run into the same issue.
At first I tried to force fragment replacement on onResume() function like so:
Fragment f = getSupportFragmentManager().findFragmentById(R.id.container);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_container, f);
fragmentTransaction.addToBackStack(null);
However android should handle all of this automatically, at least in my knowledge, and so I tried to dig further and I finally narrowed it down to my onStart() method.
Basically I was registering the EventBus and making a function call
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
UserNetworkManager userNetworkManager = new UserNetworkManager(MainActivity.mainActivity);
userNetworkManager.fetchFeed();
}
This code was creating the issue and after all it was not necessary to put it there, so I moved it to the onCreate() method, cleaned up my code a little bit and everything works fine now.

How to replace fragment properly using navigation drawer

I am using navigation drawer and it is simple to use. I am not providing the complete code but providing you detail which could be easy for you to understand my problem. I am using fragments these are about 8 in numbers and I am replacing them with one an other. But here comes a problem
I am replacing them on click event of the navigation drawer. but there are two main problems
After replacement , I can see the previous fragment in the background. does replace method just call the new fragment over it ? if yes then what should I do to old fragment not be visible in the background of my new fragment.
When I click navigation drawer Item , it loads the specific fragment successfully. but keeping in that fragment when I click to that specific item again it loads this fragment again and again. For example if drawer item num 3 opens fragment MyBook , then by clicking item num three 2 or many times would open fragment that much time.
So please some one answer me how to cure my app for such kind of actions which I described above.
I tried like this. Its working fine me
FragmentManager frgmanager = getFragmentManager();
frgmanager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
FragmentTransaction frgTransaction = frgmanager.beginTransaction();
if(subitem.equalsIgnoreCase("subitem")){
Frag1 frg1 =new Frag1(mCtx);
frgTransaction.replace(R.id.inflate_layout, frg1);
}else if(subitem1.equalsIgnoreCase("subitem1")){
Frag2 frg2 =new Frag2(mCtx);
frgTransaction.replace(R.id.inflate_layout, frg2);
}else{
Frag2 frg3 =new Frag3(mCtx);
frgTransaction.replace(R.id.inflate_layout, frg3);
}
frgTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
frgTransaction.commit();
you can use addtobackstack in fragmentstranstion object.like
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.bodyfragment, new AnotherFragment());
transaction.addtoBackStack(null).commit();
Use replace-method of FragmentTransaction instead of add (http://developer.android.com/guide/components/fragments.html#Transactions)
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.bodyfragment, new AnotherFragment());
transaction.commit();
To avoid re-instantiating the fragment, keep track of the current open fragment and only do a fragment transaction, if we next-to-be-opened fragment is a different one than the current.
This may achieved like the following:
class MyActivity ... {
private String currentFragment;
private void openNewFragment(Fragment fragment) {
String newFragment = fragment.getClass().getSimpleName();
if (newFragment.equals(currentFragment)){
// new fragment already shown
return;
}
// Fragment transaction etc here:
}
}
Note that this only compares fragments based in their class name. Sometimes this might not be unique, e.g. if there is a DetailFragment class which displays information about an entity. Which entities details to show may depend on intent arguments.
The above code however will then prevent opening DetailFragment for Entity=1 if currently details for Entity=2 are shown. For these scenarios the information about the fragment kept needs to be extended (e.g. storing a Reference or WeakReference to the fragment instance itself).

DialogFragment shows onBack button press even if I remove it

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.

OnRotate crash for DialogFragments

I have a DialogFragment that is shown on the screen from a background thread. When I rotate the screen, my app crashes. Below is the code:
public void showDialog(DialogFragment dialog) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.addToBackStack(null);
dialog.show(ft, "dialog");
}
This gives me the following error:
10-24 13:20:51.490: E/AndroidRuntime(3038): java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
After looking for answers on SO, and this article, I tried doing this:
public void showDialog(DialogFragment dialog) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.addToBackStack(null);
ft.add(dialog, "dialog");
ft.commitAllowingStateLoss();
}
But with this, I get the following error on ft.commitAllowingStateLoss()
10-24 13:26:58.890: E/AndroidRuntime(3765): java.lang.IllegalStateException: Activity has been destroyed
Any idea what am I missing?
You have a method as showDialog(DialogFragment dialog) but your problem is in your dialogFragment's initialization I guess. If you put dialogFragments initialization data to its arguments, your problem will be solved. Write a newInstance method and use it on creation of your dialog. See sample here.
Edit: Reason of your exception is; your activity and also dialogFragment is destroyed and re-created somehow(maybe by config_changes not set at manifest or "settings -> developer options -> don't keep activities" is selected. This can happen, it is normal). And initialization paramaters of your dialog has been lost(became null). You have to put your initialization parameters to dialogFragment's arguments and so it can read them after re-cration on create.
Try this:
FragmentManager fm = getActivity().getSupportFragmentManager();
dialog.setTargetFragment(this, 0);
dialog.show(fm, 0);
Are you creating the fragment using a constructor with parameters?? if so that could be the case because you are not supposed to create fragments that way

Categories

Resources