In my Android Application, I have two Fragments in my Activity, A and B.
In “A” Fragment I have developed one form and in that form some data is coming from a database. I have used a fragment transaction and replaced fragment “A” with fragment “B”.
Here is my code to replace Fragment A with FragmentB.
final FragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
FragmentB reload = new FragmentB();
fragmentTransaction.replace(android.R.id.content,reload);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
In “B” Fragment, I am fetching data from a server and storing it in an SQLite database so we can use the latest data in the application. When I click on the back button it returns back to Fragment “A” but all the data in Fragment “A” is not refreshed based on the newly-reloaded data.
Here is my code for main activity where I override onBackPressed() method:
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
getFragmentManager().popBackStack();
}
I want to refresh Fragment A's data with the latest values from the database when I hit the back button from the main activity. As much I know we cannot do back-press event in fragment B. Please correct me if I am wrong and suggest me how I can solve issue.
Does anybody know how I can achieve it?
If you want to add to back stack then you should use fragmentTransaction.add() . replace will just replace the fragment.
Also the right place to handle pop from backstack is through the use of OnBackStackChangedListener like this
getFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
// find your fragment and do updates
}
});
A good reference Fragments onResume from back stack
When back pressed your Fragment onResume will be called so you can write refresh code in onResume
for better understanding refer below link
http://developer.android.com/guide/components/fragments.html
Related
I'm having problem with fragment. Lets try to understand my issue, I have two fragment A and B. When app start with main activity,i start fragment A as you can see :
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,new MusicFragment())
.commit();
When i click on a button, it starts fragment B
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,new BarFragment())
.addToBackStack(null)
.commit();
Main problem is after starting fragment B,when i pressed back to go back to fragment A , Fragment A Recreated with new state.
I don' want to recreate fragment A. I only want to start fragment from old state where i left. How to fix it ?
Instead of calling the replace method you should be calling the add method with a subsequent call to addToBackStack with an argument of null. The add method adds the fragement to the stack with a null tag and calling the addToBackStack with an argument of null then the current fragment is stopped upon commit. If the method is not called then the current fragment is destroyed and recreated when coming back.
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container,new BarFragment())
.addToBackStack(null)
.commit();
You can clearly find it in the documentation quote saying this:
If you don't call addToBackStack() when you perform a transaction that
removes a fragment, then that fragment is destroyed when the
transaction is committed and the user cannot navigate back to it.
Whereas, if you do call addToBackStack() when removing a fragment,
then the fragment is stopped and is later resumed if the user
navigates back.
Here are some points that need to be taken care while creating fragments.
Check the backstack if the fragment is already created.
If it was created previously pop it from the backstack and put it on top so that it is visible to the user.
If fragment is not present in backstack crate it and store it in backstack.
Create a method like below which will handle such situation.
private void openFragment(Fragment fragment_to_be_opened){
String fragment_to_be_opened_name = fragment_to_be_opened.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
// fetching the fragment if it is present in backstack
boolean fragment_allready_present = manager.popBackStackImmediate (fragment_to_be_opened_name, 0);
if (!fragment_allready_present){ //fragment is not present in backstack so create it and save the name in //backstack
FragmentTransaction fragment_trasition = manager.beginTransaction();
fragment_trasition.replace(R.id.fragment_container, fragment_to_be_opened);
fragment_trasition.addToBackStack(fragment_to_be_opened_name);
fragment_trasition.commit();
}
}
Now call this method from the activity to open a new fragment like
// create instance of fragment and pass it to the open fragment method
Fragment myFragment = new myFragment();
openFragment(myFragment);
I have only one activity in my application with multiple fragments. Whenever a user opens the app, it starts with startupFragment. Whenever user navigate through the fragments and presses back, it takes him back to startupFragment. But when in the startupFragment, I want user, when clicked back, to be able to close the application. Now, here is the code, when the application is started for creating the fragment.:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Set starting fragment
StartupFragment startupFragment = new StartupFragment();
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().add(R.id.content_main, startupFragment, "startupFragmentTag").commit();
}
As you can see, I have added the tag "startupFragmentTag" to be able to identify it. This is my code onBackPressed:
#Override
public void onBackPressed()
{
Fragment startup = getFragmentManager().findFragmentByTag("startupFragmentTag");
if(startup == null) {
android.support.v4.app.FragmentManager manager = getSupportFragmentManager();
StartupFragment startupFragment = new StartupFragment();
manager.beginTransaction().replace(R.id.content_main, startupFragment, "startupFragmentTag").commit();
} else {
finish();
}
}
So basically what I tried here, is when user is in another fragment, when the user presses back, it will take him/her back to startupFragment. But when in that fragment, when pressing back again, I want the user to be able to exit the application, which won't happen given the code now.
I find the startupFragment by its tag and check if it exists. If not, it will take back the user to it. But if it exists, user should be able to quit, that why finish() is called.
Does the previous fragments not get destroyed? But that shouldn't be the case, because even if I open the app and instantly press back, it won't exit the app.
What am I doing here wrong?
It looks like all you need to do is add each Fragment to the back stack on each FragmentTransaction, and then pop each Fragment from the back stack in onBackPressed().
First, modify onCreate() so that on each transaction, it calls addToBackStack():
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Set starting fragment
StartupFragment startupFragment = new StartupFragment();
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.content_main, startupFragment, "startupFragmentTag")
.addToBackStack(null)
.commit();
}
Then, in onBackPressed(), just pop from the back stack if you're not on the starting Fragment. If you're on the starting Fragment, and back is pressed, just call super.onBackPressed(), which will exit the app:
#Override
public void onBackPressed() {
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 1) {
//Go back to previous Fragment
fragmentManager.popBackStackImmediate();
} else {
//Nothing in the back stack, so exit
super.onBackPressed();
}
}
You're working with fragments, so to finish your app you need to finish the parent activity.
Try this to finish the activity from startupfragment:
getActivity().finish();
Probably because you've used beginTransaction().add() to add the Fragments including startupFragment and other Fragments on top of it. Then you will always be able to find it using getFragmentManager().findFragmentByTag(), because all Fragments added will be in the Fragment stack (while the find method is actually to find the Fragment with the tag in the stack).
Tips based on what you want to impl:
beginTransaction().replace() will replace instead of adding a Fragment, this way you will only be able to "find" one existing Fragment if you always replace it. i.e. always one Fragment in the stack.
You may want to use getFragmentManager().findFragmentById() to get current showing Fragment (on top of the Fragment stack), instead of findFragmentByTag, if there're several Fragments in the stack which are added not replaced as mentioned above.
When using beginTransaction().add(), you may want to use fragmentManager.addOnBackStackChangedListener() to monitor the Fragment stack changes. Then you probably don't have to handle onBackPressed(). Then in the in the listener you only need to retrieve current Fragment on top stack and see what it is and add your logic there.
I have fragment A and adding fragment B in same container (not replacing). I am adding this transaction on backstack also. Now, when device back is pressed, fragment B will be removed and fragment A will become visible. I want to do something when fragment A becomes visible. I searched lot but could not find anything helpful.
Note - I don't want to add backstackchangelistner and call onResume on that fragment.
You can override onHiddenChanged(boolean hidden) in a Fragment.
This will be called when its shown/hidden.
I use the same approach in my app, where i add a fragment and hide the old one, and then use the onHiddenChanged callback when the user presses Back, and the old fragment is shown again.
As you have 2 entries in Back stack, you can check back stack count on
Back Pressed method.
FragmentManager mFragmentManager = getSupportFragmentManager();
int count= mFragmentManager.getBackStackEntryCount();
if(count==1){
// do your work
}
you can try
#Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
}
or
`fragment.isVisible();`
In my application I have two fragments A and B. A fragment contains Google map and listview inside on it B fragment Google map only.
I want open B fragment from A fragment but when I press back button it has to go to A fragment without loading data.
public void addPage(final DefaultFragment pDefaultFragment, final boolean isAddToBackStack){
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.add(R.id.content_frame, pDefaultFragment);
//transaction.replace(R.id.content_frame, pDefaultFragment);
if (isAddToBackStack) transaction.addToBackStack(null);
transaction.commitAllowingStateLoss();
}
I use this code for adding fragment
Bframent b = new Bfragment();
addPage(b,true);
I know differences between transaction. add and transaction.replace. My problem is when I use transaction.add A fragment's map doesn't destroy it stays above of B fragment's map when pressing button. But when use transaction.replace after press back button data loads again.
So could anyone tell me what should I do to Press back button without to load data without any problem on view also.
On back press just provide your fragment null;
I'm trying to decide and show a fragment in activity's onResume method, but in case a previously added fragment is chosen again, then the activity goes blank.
Sample code (with one fragment):
#Override
protected void onResume(){
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.myLayout, fragA);
trans.commit();
getSupportFragmentManager().executePendingTransactions();
}
With above code, when the activity is created for the first time, it shows fragA correctly, but in case I press Home Key and then switch back to my activity (in order to provoke onResume again), it all goes blank (seems like fragA is removed).
Is replacing a previously added fragment removes itself? or how not to loose a fragment if it is replaced by itself?
You can't replace a fragment with itself. The first half of a replace is a removal of the previous fragment at that id. Once a fragment is removed it can no longer be added or used by the fragment manager (so the add portion of the replace will not work properly).
Depending on your use case, you have two options:
Create a new fragment instead of reusing the existing instance
Use some other method to see if its necessary to replace your fragment
Finally, you probably don't need to call executePendingTransactions.
You can try:
if( !(getSupportFragmentManager().findFragmentById(R.id.myLayout) instanceof FragmentA) ) {
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.myLayout, fragA);
trans.commit();
}
And I assume that fragA is FragmentA class object.
Finally, I had to put a check before replacing fragments. In case, an (already added) fragment is requested for replace again, I had to check if its already added then ignore the replacement, else proceed. For example:
#Override
protected void onResume() {
if (!fragA.isAdded()) {
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.myLayout, fragA);
trans.commit();
//getSupportFragmentManager().executePendingTransactions(); //unnecessary
}
}
When referencing back to a created Fragment please do make sure to try adding the
fragmentTransaction.addToBackStack(null);
method right before committing so that your Fragment is resumed instead of destroyed as mentioned in the developer guides.
If you don't call addToBackStack() when you perform a transaction that removes a fragment, then that fragment is destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you do call addToBackStack() when removing a fragment, then the fragment is stopped and is later resumed if the user navigates back.
You can find this at the end of this page.