Considering I have a navigation view and few fragments associated with it. I wanted to end the fragment when transited to another
For example if Im in fragment A and I click fragment B (or any), The fragment A should get closed or destroyed.
Note: fragmentTransaction.replace(R.id.container, fragment); doesn't work
code for transaction
if(fragment!=null){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.fl, fragment);
ft.commit();
}
Based on the comments, you're WebView isn't getting unloaded when your Fragment transitions. To resolve this, call webView.stopLoading(); and webView.destroy(); from either the Fragment's onPause() or onStop() callback. you may also want to wrap both of those calls in a null check just in case webView actually does unload. So your code block will look something like this:
if(webView != null){
webView.stopLoading();
webView.destroy();
}
that's easy and handling automatically from android side , just enough after to replace your fragment don't do .addToBackStack(null) and when you go to next fragment , last fragment gone
Related
Working with fragments I've always used replace() for my transactions, but I wish I didn't have to save instance states anymore to restore a fragment's view and prevent reloading when coming back to that fragment. So, I've decided to work with add(). The thing is when I add another fragment, the previous fragment view remains in the background and that's fine (that's the behavior I expected), but the problem is I can actually interact with the views in the background. Example:
Fragment A has a Button
Fragment B has a TextView
When I add Fragment A and later add Fragment B, I'm able to click on Fragment A's Button, even staying on Fragment B's view.
I'm using:
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction().
add(getRootViewContainer(),fragment,fragment.getClass().getSimpleName());
if (shouldGoBack)
fragmentTransaction.addToBackStack(fragment.getClass().getSimpleName());
where getRootViewContainer() returns the id of the FrameLayout I'm using as my activity main container.
Now, is it really the default behavior of add()?
If so, is there a proper way to avoid this or one just has to use replace()?
What you can do here is just hide previous fragment at the time of transaction of current fragment.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment newFragment= new MyFragment ();
ft.hide(CurrentFragment.this);
ft.show(newFragment);
ft.commit();
It worked for me just try it.
FragmentTransaction.hide(fragmentBehind); //works for me!
example :
//I have it globally available
FragmentTransaction trans = MainActivity.getManager().beginTransaction();
//not globally
FragmentTransaction trans = getFragmentManager().beginTransaction();
MapFragment newFragment = new newFragment();
trans.add(R.id.fragmentContainer, newFragment, tag);
trans.hide(this);
trans.addToBackStack(tag);
trans.commit();
Yes, this is a default behaviour of add().
If you really don't want to user replace(), you can try to disable views which are inside "old" fragment.
I have a situation in which I need to show/hide a fragment based on a dynamic variable. My question is should I create the fragment once, and then show/hide based on the variable. Or should I destroy/create it each time?
Create the fragment
Fragment alertFragment = new AlertFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(android.R.id.content, alertFragment).commit();
After this should I call show/hide each time?
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
.show(alertFragment) // or hide
.commit();
Seems like a lot of work to show/hide something each time. Is this the right way to do it?
I'd say that depends on weather it matters for your application if your Fragment is destroyed or not.
If it doesn't matter at all, simply replace the Fragment everytime by a new one. This is the simplest solution and does not require any logic.
Fragment f = new Fragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content, f).commit();
I've setup a new Android project that comes with an activity. Here's the boiler plate code:
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
Can someone explain what this is doing exactly? From what I can see, it checks if the activity hasn't been initliazed and then inflates the layout. But what I don't understand is beginTransaction(), ew PlaceholderFragment(), and commit()
Thanks.
You use fragment transactions to add / replace (etc) fragments within a FrameLayout (R.id.container) and new PlaceholderFragment is a new instance of a fragment to be put into the container
//Check whether we're recreating a previously destroyed instance
if (savedInstanceState == null) {
//Execute a transaction, replacing any existing fragment with this one inside the frame.
//Getting FragmentManager object which will control fragment acvitiy
FragmentManager fm = getFragmentManager()
//Starting a FragmentTransaction which will handle transaction to this fragment activity
FragmentTransaction ft = fragmentManager.beginTransaction();
//Add a fragment to the activity state. This fragment may optionally also have its view (if Fragment.onCreateView returns non-null) into a container view of the activity.
ft.add(R.id.container, new PlaceholderFragment());
//Schedules a commit of this transaction.
ft.commit();
}
There is a good explanation to fragment activity here, here and here
FragmentManager is a class which helps in managing the fragments that an activity may need. So here you are basically getting an instance of it and you are beginning a transaction. You need an instance of transaction because it lets the runtime know that some change is going to happen when this is called. Here 'add()' is that change and finally you commit it to save that change.
The arguments to add are the layout where the fragment needs to be added and the PlaceHolderFragment() is the name of the Fragment you need to put in.
As fragments are the way to go, replacing all of many heavy Activites, Eclipse has also adapted to this change which cause the boiler alert. :)
Starting a fragment (which cant be done via Intents) is treated as a transaction just like in database (not a good example i guess).
getFragmentManager() - gets the Activities FragmentManger which is responsible to initiate FragmentTransaction.
beginTransaction() - creates a new Transaction for this particular fragment job.
new PlaceholderFragment() - is an instance of the PlaceholderFragment which you can find if scroll more in the Activity.
commit - a way to commit this trasaction and bring it to effect.
See Android docs. for more details. :)
It is simple my friend.
In simple Coding Language:
if (savedInstanceState == null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.tab5, new PlaceholderFragment());
fragmentTransaction.commit();
}
If you think that it explain everything, then it is a pleasure for me. Otherwise just ping me to add theory information.
Hello I am working with sliding menu with fragment.
Indivisual fragment works properly. But suppose user navigates From fragment A->B , now 'B' works perfect and now if user goes from B->A than fragment 'A' is called from onAttach() .
I want such a condition if any fragment is opened , than reopening it should not load whole fragment , it should be resumed just like we handle activity with Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.
Here is my code...
FragmentManager fm = MainActivity.this.getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Layout1 fragment = new Layout1();
ft.add(R.id.activity_main_content_fragment, fragment,Layout1.class.getName());
ft.addToBackStack(Layout1.class.getName());
ft.commit();
Answer updated:
Reading the documentation, there is a way to pop the back stack based on either the transaction name or the id provided by commit. Using the name may be easier since it shouldn't require keeping track of a number that may change and reinforces the "unique back stack entry" logic.
Since you want only one back stack entry per Fragment, make the back state name the Fragment's class name (via getClass().getName()). Then when replacing a Fragment, use the popBackStackImmediate() method. If it returns true, it means there is an instance of the Fragment in the back stack. If not, actually execute the Fragment replacement logic.
private void replaceFragment (Fragment fragment){
String backStateName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);
if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();
}
}
If you return to a fragment from the back stack it does not re-create the fragment but re-uses the same instance and starts with onCreateView() in the fragment lifecycle, see Fragment lifecycle.
So if you want to store state you should use instance variables and not rely on onSaveInstanceState()
Check this link. it will help How to resume Fragment from BackStack if exists
I have following issue with Android compatibility package fragments.
There is following hierarchy of fragments:
A(login) -> B(dashboard) -> C(details)
Login fragment is added with function:
private void addFragment(Fragment f) {
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.replace(R.id.main_content, f);
ft.commit();
}
After successfull login dashboard is added same way, without adding transaction to backstack. C fragment is added like:
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.main_content, f, id);
ft.addToBackStack(null);
ft.commit();
So basically on detail screen I have logout button, which should bring me to login A and remove all fragments from backstack. According to android developer docs:
Whereas, if you do call addToBackStack() when removing a fragment, then the fragment is stopped and will be resumed if the user navigates back.
But it is not the issue in my case. When logout is pressed in C fragment:
getFragmentManager.popBackStackImmediate();
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.replace(R.id.main_content, new LoginFragment());
ft.commit();
onActivityCreated(), onStart() of B fragment are also called (instead of onResume written in docs), making my code crash because in this fragment Im starting some thread operation, and after adding login fragment I got IllegalStateException that fragment B is not attached to an activity (when thread operation is over it updates fragment UI) Do anyone knows how replace really works and how overcome this problem?
I guess you should call
addToBackStack for each fragment you add giving a different name to them.
Reading your code seems to me you don't do it.