Bundle in a fragment created - android

Is there anyway to assign a Bundle to a fragment already created?. I tried something like this:
Bundle mArgumentos = new Bundle();
mArgumentos.putString("id", id);
this.setArguments(mArgumentos);
But I get the error: Fragment already active.
I'm just wondering if I can achieve this without overriding the onBackPressed() method.
My purpose with this is because I have a form for registry a new item. From here I can go to another fragment (lets call it fragment_B) with the new id of the item (I call fragment_B with a bundle assigning the new id). When the user presses back button, he gets to the previous form but the id is missing (this is because the form goes to the previous state, like empty), so if he tries to go to fragment_B again, he cant because the id.
Obviously the user cant go to fragment_B if the form has not been save. So the user saves the form and then press the button to go to fragment_B with its new id:
FragmentB fragment = new FragmentB();
Bundle mArgumentos = new Bundle();
mArgumentos.putString("id",id);
fragment.setArguments(mArgumentos);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(android.R.id.tabcontent, fragment, tag);
ft.addToBackStack(tag);
ft.commit();
Any suggestions?.
Edit:
The fragments are not in the same activity. When I create a new item and press button save I should be in a "edit mode". This means that after I create the item I can come back and edit it. I'm just using the same fragment to edit and create. So, when I create the item, press the button to go to fragment_B and then press back button, I should be like "edit mode" of this item. This means that from fragment_B to the previous I should pass the id of the item created. That's why I wanna know if I can do this without overriding the onBackpress method.
Edit2:
If there is no other way to achieve this, I was thinking in override the onBackpress method like this:
//get the fragment where I'm staying on.
Fragment fragmentActual = this.getSupportFragmentManager().findFragmentById(android.R.id.tabcontent);
//get the tag of the fragment
String fragmentTag = fragmentActual.getTag().toString();
if (fragmentTag.equals("tagFragmentB")){
Fragment fragmentA = new FragmentA();
Bundle mArguments = fragmentActual.getArguments();
String id = mArguments.getString("id");
if(id != null){
fragmentA .setArguments(mArguments);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(android.R.id.tabcontent, fragment, "fragmentA");
ft.addToBackStack("fragmentA");
ft.commit();
}
}else{
super.onBackPressed();
}
This is working but as you have notice, this change the order of the fragments called by the user and this should be invisible for the user. So, this forces me to put more code in order to get the calls that the user did.
I'm kind of new with this, so maybe I have not the "Android thinking". If is there a better way to do what I want, I'm open to everything. I just want to do the thinks right and dont have problems in the future just because a user pressed a back button.

Well in my particular situation a made it work doing the following: I noticed that when I fill the form, saved it, then go to fragmentB and finally press back button, the information of my form was retained. So I put a hidden etidText in my form:
<EditText
android:id="#+id/textEditHiddenId"
android:visibility="gone"
android:inputType="number" />
When the button save is pressed, I set the content of this editText:
etIdHidden.setText(id);
When the activity is created, according to http://developer.android.com/guide/components/fragments.html, the method onResume is called after the onCreateView. So, I get the value of my textEditHiddenId in this method:
#Override
public void onResume() {
super.onResume();
String id= etIdHidden.getText().toString();
if(id.equals("")==false){
mArgumentos=new Bundle();
mArgumentos.putString("id", ""+id);
}
};
The first time, the content of textEditHiddenId is empty, but when backbutton is pressed and the onResume method is called, I get the content initialized and I can override my Bundle.
Simplest solution ever..

Related

How to save previous values in fragment while we switch to other fragment and return to last one

I have a fragment (say FragA) gets and another fragment (say FragB).
In FragA I set some values seekbar and put a check on checkbox
but now if click on FragB and then click on FragA then all set values are gone.
For fragments I have used a ListAdapter which set a fragment depending on position no. where I clicked. I don't want it on back button press but on clicking that fragment.
My Question is how can I restore a fragment to its previous state while setting parameter in other fragments and clicking to those fragments which I set before.
Make use of onSaveInstanceState(), below is the example how you need to implement it
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
And later you can use it like this:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
}
It will be a good idea if you go through fragments documentation
You can save each transaction to a back stack managed by the activity, allowing the user to navigate backward through the fragment changes (similar to navigating backward through activities).
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Before you call commit(), however, you might want to call addToBackStack(), in order to add the transaction to a back stack of fragment transactions. This back stack is managed by the activity and allows the user to return to the previous fragment state, by pressing the Back button.
detail

Fragment switching views being reused?

I have an Activity with a FrameLayout and need to show different fragments based on user input.
The code I use for showing a fragment is this:
private void showFragment(Fragment fragment, Bundle args, boolean addToBackStack) {
if (args != null) {
fragment.setArguments(args);
}
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.activity_open_translate, R.anim.activity_close_scale);
fragmentTransaction.replace(R.id.main_frame, fragment);
if (addToBackStack) {
fragmentTransaction.addToBackStack(fragment.getClass().getName());
}
fragmentTransaction.commit();
}
This is called as :
if (contactPickFragment == null) {
contactPickFragment = new ContactPickFragment();
}
showFragment(contactPickFragment, args, true);
All this works fine. Now if the user goes into one fragment presses back and returns back to the same fragment, all my views inside stay the same. For example, I have an EditText inside the fragment and the user edits something inside. If the user comes back to the fragment, the same text persists. I do not want this to happen. How do I reset everything in the view?
I have added code within the Fragment's onCreateView() to clear the text, and from debugging I see that this is being called, but the text never gets cleared. What am I doing wrong here?
If you don't want the data from the previous instance to appear, simply create a new instance of ContactPickFragment each time you show it.
Clearing data in onCreateView() has no effect because view state is restored AFTER onCreateView(). Your Fragment has no view before onCreateView() and so Android cannot possibly apply the previous state any earlier. Values set on the views during onCreateView() will be overwritten by their previous values.
As a general answer, there is no way to "refresh" the view of a Fragment, other than replacing the fragment with another instance of itself (possibly initialized with the parameters that you want to refresh/update).
You can reuse your fragments and refresh the state of your views. You just can't do it from onCreateView as #antonyt correctly points out.
Instead, override onViewStateRestored and set up the state of your views the way you'd like from there.
Something like:
#Override
public void onViewStateRestored(Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
View view = getView();
// Code to call view.findViewById to grab the views you want
// and set them to a specific state goes here
}
There are advantages to reusing fragments. Not the least of which is that if you have a memory leak with your fragment (which is easier than you may think to accomplish,) you will exacerbate the problem by creating myriads of them.

Fragment and Host Activity Commnication

I have this design problem. I have an activity which hosts two fragment and any given point of time only one activity is visible.
Activity A hosts Fragment B and Fragment C
Host Activity A implements FragmentCommunicator interface and implement respond(int code) method using this method communicator both Fragment B and C can talk to host Activity.
Now here is the problem.
In onClick of Host activity I check certain condition and based on that I take decision which fragment to show.
public void onClick(View v) {
switch (v.getId()) {
case R.id.some_button
if(authNotedone)
showFragmentA();
else{
EDIT: //setting some properties before showing Fragment B
showFragmentB();
}
}
}
So far it works fine. If condition is true FragmentA will be visible with login form. After successful login I would like to show fragment B again. How can I achieve this.
What I have tried?
1) After successful login Fragment A send message to Host activity using Fragmentcommunicator's respond(code) method but it was ugly design as I have to either call performClick() or call showFragmentA() in respond method if code is success.
There could be multiple such conditions in my program How I can handle these neatly?
Use a interface as a call back to the activity. Once you get the message in the activity there is no need to click the button just replace the existing fragment in the container.
Implement the interface in the activity
FragmentB newFragment = new FragmentB();
Bundle args = new Bundle();
args.putInt("key", "message");
newFragment.setArguments(args);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
// replace with fragmentb. no need to perform click again.
// based on the message you decide which fragment you want to replace with
transaction.commit();
You can find an example #
http://developer.android.com/training/basics/fragments/communicating.html
Do you want to navigate between fragments? If so, why don't you implement navigation tabs, have a look at this link.

how to know which fragment called another fragment?

I have this issue in Android. Consider three Fragments: A, B, C. C can be called from A or from B. Is there anyway to know from which fragment, C was called?
Edited
Ok guys I'm going to explain what I'm trying to do. Suppose I have this call: A calls B, B calls C.
When I press the back button in C It gets me to B, thats fine. But when I press the back button again, it takes me to C, instead of A.
This is my code:
#Override
public void onBackPressed() {
//this is the current fragment
Fragment fragmentActual = this.getSupportFragmentManager().findFragmentById(android.R.id.tabcontent);
String fragmentTag = fragmentoActual.getTag().toString();
//If I press the back button in C:
if(fragmentTag.equals("TAG C")){
Fragment removefragment = this.getSupportFragmentManager().findFragmentByTag("TAG B");
Fragment fragmentClient = this.getSupportFragmentManager().findFragmentByTag("TAG C");
//If Im NOT passing arguments to B, I know this is a new form
if(removefragment.getArguments()== null){
//I always pass arguments to fragment C, but just in case:
if(fragmentClient.getArguments()!= null){
Bundle mArguments = fragmentClient.getArguments();
//FRAGMENT B
FragmentB fragmentB = new FragmentB ();
fragment.setArguments(mArguments);
FragmentManager manager = this.getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.addToBackStack(null);
ft.replace(android.R.id.tabcontent,fragmentB,"TAG B");
ft.commit();
}
}else{
super.onBackPressed();
}
}else{
super.onBackPressed();
}
}
Now I'm going to explain the code. Basically what it does is to replace fragment B, when fragment C is called. I do this, because I need to pass arguments to fragment B. But when I do the replacement, the "history" of the fragment B is lost, I mean when I press back button in B, I cant go back to fragment A (HERE IS WHY I WANTED TO KNOW IF I CAN KNOW WHO CALLS WHOM).
The firts time when I call fragment B, I dont pass arguments because is a blank form. But when I call to C, staying in B, I need to pass arguments to fragment B (when back button is pressed), so It can shows updated information.
Please if there something that is not clear, let me know so I can explain myself better.
Edited 2: This issue has something with this https://stackoverflow.com/questions/16703604/back-press-button-when-i-save-a-form-for-the-first-time-a-list-view-is-not-updat. Maybe it does my idea more clear.
The answer of Luksprog I think is the best: "You may want to tackle those issues. You always have the option of passing a Bundle with data to the newly created fragment mentioning who called it. Then using getArgument() in the fragment will know who called it.".
I haven't found another better way.
You can use the setTargetFragment method to set which was the parent fragment. Then you can use the method getTargetFragment to find out who called you.
What you are doing is transitioning between Fragments, call addToBackStack() as part of your FragmentTransaction:
i guess, This is what you need.
private final static String TAG_FRAGMENT = "TAG_FRAGMENT";
private void showFragment() {
final Myfragment fragment = new MyFragment();
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment, fragment, TAG_FRAGMENT);
transaction.addToBackStack(null);
transaction.commit();
}
#Override
public void onBackPressed() {
final Myfragment fragment = (Myfragment) getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT);
if (fragment.allowBackPressed()) { // and then you define a method allowBackPressed with the logic to allow back pressed or not
super.onBackPressed();
}
}
You can use FragmentManager for creating a back stack of your fragments. You also have to work with Fragment Transactions first. Further informations see: http://developer.android.com/guide/components/fragments.html#Transactions

Fragment Replacing Existing Fragment

I have the MainActivity, it contains ListFragment and framelayout, I am able to change the fragments on list on item click.
I have a problem to replace the existing Fragment1 with the new Fragment2, on button click of Fragment1, Fragment2 should replace the Fragment1, and should have the same ListFragment at left, and back buttons should be properly handled,this means when I am in Fragment2 and press back button it should show the same ListFragment and Fragment1.
You need to use .replace to switch the two fragments, you also need add add the original to the backstack so you can recall it, and you need to override the back key operation to function that way. It would look something like this (using code from one of my projects, using the support library):
To show your first fragment:
menu = new MenuFragment_Main(); // instantiate fragment
getSupportFragmentManager().beginTransaction().replace(R.id.pane, menu).commit(); // display fragment
To swap it for the new fragment and add it to the backstack:
ListFragment_ShopListItem shoplist = new ListFragment_ShopListItem(); // instantiate fragment
getSupportFragmentManager().beginTransaction().replace(R.id.pane, shoplist).addToBackStack(null).commit(); // replace original fragment with new fragment, add original to backstack
And to override the back key to go back to the previous fragment:
public void onBackPressed() {
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.popBackStack();
return;
}

Categories

Resources