Android replacing fragment doesn't remove text field data - android

Lets say I have 2 fragments, one of which has a text input field.
I switch between my fragments in the main activity with this:
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_new) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, NewFragment(), fragment.getClass().getSimpleName())
.addToBackStack(Integer.toString(id))
.commit();
} ...
Notice I'm using framentTransactions replace method
On the current fragment with the input box, I type in some text. Then I use the nav bar to switch to a new fragment. I would expect that because I'm using replace, the old fragment no longer exists.
I navigate to the new fragment fine, but when I press the back button, the old fragment still has the text that I typed in previously
Why would this happen when using replace? Am I misunderstanding how fragment transactions work?
Does the onCreateView method of the fragment not get called again when I press back, thus essentially resetting the fragment?

You have to clear your textfied manually when you switching to another fragment
Because fragment replace is only replace fragment but still your old fragment is there without any change .

Related

Switching Activities

I've been researching a solution to my problem but not a single result fixes my problem.
I have five Java activities. Each activity has five buttons, four to the other activities and one to itself. It's basically just a bar of bottoms at the bottom of the page.
My issue is that let's say I'm in one activity, and then I click that button to the activity again, it opens and loads an entirely new activity. And then when I click back, it shows the previous activity open as I left it. But if I press it ten times, I need to click back ten times. Also, if I switch between each activity twice and I want to click back to main to exit, I need to click back ten times instead of five.
I want it to be such that when I click a button, it opens the activity. If I press the button again, it does nothing if I'm in that activity. And if I'm switching between activities and I repress an activity I already opened, I want that to be brought to the top of the stack from its lower location, not added. So at most, I only want five activities running.
It's a very confusing problem as I see people suggesting to use intent flags, which I'm not sure if I place them in the manifest, which does nothing with I try. And I've seen people suggest using LaunchMode single instance, which also does nothing.
I really think fragments are the best method here. And yes, it's a little tricky but you can use fragments within fragments. For navigating without creating extra instances, I think you might be looking for something along the lines of this:
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if(id == R.id.nav_home){
Fragment newFragment;
FragmentManager fragmentManager = getSupportFragmentManager();
// Look for fragment by tag
Fragment foundFragment = fragmentManager.findFragmentByTag(MAIN_FRAGMENT);
if(foundFragment != null) { //if fragment's already in the backstack
newFragment = foundFragment; //replace fragment with backstack fragment
}else{
newFragment = new MainFragment(); // use a new fragment instance
}
// Add new fragment instance to fragment manager
fragmentManager.beginTransaction()
.replace(R.id.fragment_container, newFragment, MAIN_FRAGMENT)
.addToBackStack(MAIN_FRAGMENT)
.commit();
}
// ...
}

Fragment with AsyncTask and Navigation Drawer - Best practice

I write this question because I would like to know which is the best way to manage this context: I have a MainActivity with Navigation Drawer and whenever I select an item in Navigation Drawer, I create a new fragment and through the FragmentTransaction I replace the previous fragment with the new one.
Now, in every fragment I have an AsyncTask that performs some task (eg download data from web or perform a query on a local sqlite database).
My question is: how can I avoid to recreate every time the fragment and restart AsyncTask when I press an element in Navigation Drawer? Which is the best way to manage this situation?
This is the method that I use in MainActivity to display fragment when I press an item in Navigation Drawer:
private void displayView(int index) {
Fragment f = null;
switch(index) {
case 1:
f = Fragment1.newInstance();
break;
case 2:
f = Fragment2.newInstance();
break;
}
if(f != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.container, f);
ft.commit();
}
}
Thanks in advance!
Hiding a fragment is an alternative to removing it. Removal (if not added to the backstack) causes the fragment to be completely torn down (pause, stop, destroyView, destroy, detach). Hiding doesn't change the fragment's lifecycle state, it just makes it not visible. The FragmentTransaction methods are hide() and show(). Initially, you would add both your fragments, and then hide the unselected one. When a fragment is selected from the navigation drawer, if it is not already visible, you would hide the old selection and make the new selection visible. Something like this:
getSupportFragmentManager()
.beginTransaction()
.hide(oldSelectedFrag)
.show(newSelectedFrag)
.commit();
The visible/hidden status of a fragment is available using isHidden(). There is also a Fragment callback: onHiddenChanged(). Keep in mind that when a fragment is hidden it is still active in the sense of being in the started or resumed state. You may want to use the hidden status to disable refreshes or other actions that are only needed when it is visible. If the fragment has an option menu, you may also want disable that using setMenuVisibility() when the fragment is hidden. I don't think the FragmentManager does that for you automatically.

Android BackStack NavigationDrawer

I have a problem that I've been dealing with for the last couple o days and don't seem to find an answer to it.
Description : I have a main activity which contains a navigation drawer. Each item of the navigation drawer (when clicked) creates a fragment. In that fragment, there is a listView of objects, which creates other fragments when clicked. In those fragments i have another listView of objects which opens other fragments. In other words, there series of fragment that open other fragment. Something like this:
http://s22.postimg.org/pddo5gsv5/backstack.png
In order to be able to get back to each fragment, I've implemented the addToBackstack("string") method.
My question is, how can I implement correct backstack for my application so that when i click a navigation Drawer item, all the fragments that have been added to backstack are cleared, without the one that the navigation Drawer item opens.
Any help would be appreciated. Thank you !
EDIT
Ok, it seems I managed to figure it out. Considering what advices i received from the replies, here's the solution I came up with:
#Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if (count != 0) {
FragmentManager.BackStackEntry backEntry = getFragmentManager()
.getBackStackEntryAt(
getFragmentManager().getBackStackEntryCount() - 1);
if (backEntry.getName() == NAVIGATION) {
finish();
} else
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
To put it in words: First, i added a backstack entry even for the top level fragments, given them a specific tag. The I have overridden the Activity's back button function so that when the last backstack entry is a top-level fragment to finish the activity (so that it not simply detach the fragment from activity, living it empty). Otherwise, if the last entry isn't an top-level fragment, execute a popBackStack.
PS: All non-top-level fragments are added to the backstack with a different tag then the top-level one. Also, i had to do a POP_BACK_STACK_INCLUSIVE in the navigation Drawer's click listener.
getFragmentManager().popBackStack(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
Thank you all for the advices and hopefully this EDIT help other users.
You can use the following code to solve your problem:
getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(fragment_tag)
.commit();
In order to make the code above work, you have to create the fragments dynamically. As hardcoded fragments cannot be replaced. To do that, you can create a container (FrameLayout etc.) which in our example has the id fragment_container. Then, the code above will add the fragment in the container dynamically. Finally, you have to pass as parameter in the addToBackStack method the fragment_tag. That means, that this transaction will be added in the back stack. And finally, in order to get it from the backstack you have to use the code below:
getFragmentManager().popBackStack(fragment_tag, FragmentManager.POP_BACK_STACK_INCLUSIVE));
The POP_BACK_STACK_INCLUSIVE flag, insures that "all matching entries will be consumed until one that doesn't match is found or the bottom of the stack is reached. Otherwise, all entries up to but not including that entry will be removed."
You can clear the fragment backstack by using something like:
fragmentManager.popBackStack("string", FragmentManager.POP_BACK_STACK_INCLUSIVE);
and then you can addToBackstack and commit as usual. More info.
A code snippet that shows the way I normally use it in navigation drawers:
FragmentManager fragmentManager = getSupportFragmentManager();
if(clearBackStack) {
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
if(!clearBackStack) {
ft.addToBackStack(null);
}
ft.commit();

Need suggestions with ActionBar, Navigation Drawer and back stack

I have an ActionBar activity. In this activity I have implemented Navigation Drawer from Android API.
One option of navigation drawer set a ListFragment with some elements inside its list.
When I click some elements I want to create a new fragment and set previous ListFragment to the stack. Also I want to destroy this new fragment by clicking ActionBar home button, in order to return to the previous ListFragment.
My problem comes here: When I click home button of the actionbar, drawer layout is displayed, instead of destroy the fragment... What should I do?
I have Overriden onOptionsItemSelected method in the fragment:
#Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case android.R.id.home:
getFragmentManager()
.popBackStack();
}
return (super.onOptionsItemSelected(menuItem));
}
Also I have set ListFragment to the backstack when Inflating the new fragment:
getFragmentManager()
.beginTransaction()
.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right)
.replace(R.id.activity_main_fragment_container, fragment)
.addToBackStack(null)
.commit();
Well, as the docs say here, popBackStack() is async. I suppose that the drawer layout is displayed because you call super.onOptionsItemSelected(menuItem).
I suggest you to return true for all cases you handle this selection by yourself (in this specific situation: case android.R.id.home:), and call getActivity().onBackPressed() (assuming that by pressing hardware back button the last fragment gets removed, as it should) instead of popping back stack directly. I've implemented a similar solution and it works for me.

Back key to pop the Fragment shows overlapping fragments

I created a sample app to test this overlapping issue.
I have a fragment type, Fragment1, and I create a new instance of Fragment1 and add it to a FrameLayout in my activity at runtime. I add the fragment with the help of a few buttons.
Note: I have given each new instance of Fragment1 a different number(#1, #2, #3, etc.) to display on the UI to help me figure out which fragment I am viewing.
So.. here is what I do:
Click on Button 3, create new instance of Fragment1 and add it to Frame1.
Click on Button 4, create new instance of Fragment1 and add it to Frame1 and add it to the fragment backstack.
Repeat 1 and 2.
Repeat 1 and 2.
Now, I have fragments in this order: 1(#1),2(#2),1(#3),2(#4),1(#5),2(#6).
I press the back key when viewing fragment #6.
Back key press, UI displays (#5).
Back key press, UI displays (#3 AND #5),
Back key press, UI displays (#1, #3, AND #5)
It seems fragments are getting displayed ON TOP of each other.
WHY? Is there an overlapping issue? How can I clear out this overlapping issue. I thought this would be an issue on the compatibility library... but it is also on 3.0.
Code for adding fragments:
public int doFragmentChange(int cont1, Fragment frag1, String tag1, int cont2, Fragment frag2, String tag2,
boolean addToStack, String stackTag) {
FragmentManager fm = getFragmentManager();// getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (frag1 != null) {
ft.replace(cont1, frag1, tag1);
}
if (frag2 != null) {
ft.replace(cont2, frag2, tag2);
}
// add fragment to stack
if (addToStack)
ft.addToBackStack(stackTag);
return ft.commit();
}
If you perform two add calls one after the other (two commit calls) then yes the fragments will appear overlaid, one on top of the other effectively.
So (for new example) if say you replace frag1 with frag2 and then frag3 with frag4 in the same frame with no backstack transaction then I would expect frag2 and frag4 to be overlaid.
Furtheremore there is also a potential issue in your chaining of replace. You should call a separate commit for each. See Android — Replace Fragment Back Stack With New Stack?.
Just override the onBackPress() or onKeyUp and remove the top fragment.

Categories

Resources