My parent activity is launching another activity and needs its fragments to update when the results are returned via onActivityResult. Should I simply implement methods in each fragment to pass the data into them, or is there a different way this should be done?
Thanks!
Make your fragment that should receive data implement an interface with a suiting method.
In the activity when the result is returned from onActivityResult, use the getFragmentManager().findFragmentByTag("yourtag") method to find the fragment. Cast it to the interface and call the method is has.
Make sure to check if the fragment actually exists after calling findFragmentByTag.
If the fragment is the one making the startActivityForResult call, the activity gets the first shot at handling the result. This makes sense when you consider the modularity of fragments. Once you implement super.onActivityResult for all unhandled results, the fragment got a shot at handling the result.
To get the result in your fragment make sure you call : startActivityForResult(intent,123); instead of getActivity().startActivityForResult(intent,123); inside your fragment.
I hope this will solve your problem.
Someday I will have to solve your issue or similar. Per my understanding, you'll have to implement an interface between Activity and a Fragment. The link is at Communicating with Other Fragments . The webpage seems clear unlike other Google pages. A snippet of code:
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
Almost always, class FragmentTransaction is involved in managing data. Note how Bundle is used to pass data, also to get data from the client side.
Have fun, keep us posted.
Related
Is there a way to know which Fragment is currently displayed in a given <fragment> container of an Activity without keeping track of all the changes via the onAttachFragment callback?
Is it even possible to know which fragments are displayed when fragment transactions can take place when the user presses the back key? In this latter case, i.e. when a Fragment is re-displayed due to a back, the onAttach is not called.
In my experience, the only way to know for sure which fragment is being displayed is to keep track of that carefully yourself.
For example, you could make a variable in your Activity:
Fragment mCurrentDisplayedFragment;
and then whenever the user requests a different fragment do:
mCurrentFragment = (Fragment) userRequestedFragment;
fragmentManager.replace(container, mCurrentFragment, tag);
Then, whenever you needed to do things to the currently displayed fragment, you could triage it by try/catching a cast or with instanceof.
You could also handle the back pressed behavior by overriding that method in the activity:
#Override
public void onBackPressed() {
int stackSize = fragmentManager.getBackStackEntryCount();
// This counts up from the bottom so the most recent fragment is the biggest number/size
backFragId = fragmentManager.getBackStackEntryAt(stackSize);
// Get a handle on the fragment that is about to be popped
mCurrentFragment = fragmentManager.findFragmentById(backFragId);
super.onBackPressed();
}
Also, are you sure that onAttach is not called when a fragment is popped off the stack? I seem to remember that it will be, and you can call through the interface created there (if you have one and the activity implements it) to register the fragment as the current fragment in the activity at the time.
But to directly answer your question, there isn't a built in way to just know what fragment is currently displayed (and there could be more than one!). The implementation details of that are up to you. Hopefully I've given you some ideas of how it could be handled though. You might also find the FragmentManager documentation helpful.
Each time when you add/replace fragment to the container, use tag for it:
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.container, fragment, tag).commit();
then you can find out the fragment is current visible or not:
Fragment fg = getFragmentManger().findFragmentByTag(tag);
if(fg.isVisible())
//fg is the current visible fragment
Hope this help!
I have container activity that has framelayout for storing fragment inside it.
For example I have activity with initial framgent for login page. Theare are two buttons Login And Register.
User can click register and in this case I need to change my current fragment with another fragment with registration fields.
So I have only idea to make an host activity implement callback interface and than pass activity to fragment, and when user clicks register callback method is called and host activity replacing fragment.
So the question is if there is any other better way to do this, maybe more correclty.
Please leave your suggestions and how do you deal with this problem.Thanks
You can replace fragments as follows ,
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(<container id>, new RegisterFragment());
transaction.commit();
//if you are using support library, make sure to use getSupportFragmentManager()
is there a way to send some data from an activity to a running fragment?
In my app I'm adding a second fragment over another fragment. I intentionally use the add method instead of the replace method. So now I want to hide my second fragment with
fragmentManager.popBackStack();
and my first fragment reappears. After hiding the second fragment I want to send some data from my activity to the still running frist fragment.
Any idea how to do this? It doesn't work with bundles (put extra), because I don't rebuild the fragment, I just hide the second one!
one simple solution is:
MyFragment oldFragment = (MyFragment) fragmentManager.findFragmentById(R.id.fragment_place);
fragmentManager.popBackStackImmediate();
MyFragment newFragment = (MyFragment)fragmentManager.findFragmentById(R.id.fragment_place);
newFragment.postData(...);
You can use an EventBus library like this one, it's easy to use and very convenient.
You can use tags on the Fragments when you create them to call them when needed.
getFragmentManager().beginTransaction()
.add(R.id.content, new SomeFragment(), SomeFragment.class.getSimpleName())
.commit();
So above I use the simple name of the class to tag the fragment when I create and add it to the activity.
SomeFragment fragment = (SomeFragment) getFragmentManager().findFragmentByTag(SomeFragment.class.getSimpleName());
And I can call it back when I need it and know it is being displayed like above, now I can call send it data like normal by calling a public method in the custom fragment and passing it the data as a param.
I have an activity where I dynamically replace fragments:
private void goToFragment(Fragment newFragment, String tag) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, newFragment, tag);
ft.addToBackStack(null);
ft.commit();
}
Now, I want to access the views inside the fragment so I can put data (that I have stored in my activity) into them, immediately after calling goToFragment.
The problem is, the fragment's onCreateView isn't called before the fragment is rendered completely, at least to my understanding.
I know overriding the onAttach(Activity activity) in the fragment is one way to go about it, but then I have to cast it specifically to my activity - and I just want to avoid that because I consider it bad practice for the fragment to be dependent on a specific activity.
As far as I can see, Fragment doesn't have any listeners (as a subject) implemented.
So I figure I have to make my own listener (Using the Observer Pattern to make the fragment a subject and the activity an observer), and then calling it whenever the onCreateView or onAttach is done, and then finally calling back to the fragment with the data that needs to be set. However, I need to do this for several fragments so I would have to make a listener for each fragment, which I again think is bad.
Is there any better/easier way to do this?
FragmentTransaction isn't applied instantly after calling commit(). You may force update manually:
...
mFragmentManager.executePendingTransactions();
AFAIK event callbacks' purpose is custom communication with Fragment beyond it's usual lifecycle.
The correct way to do it would be to define an interface for Activity classes wishing to display your Fragment should implement. That way, on onAttach you don't cast to a specific Activity but to your interface.
See for instance: http://developer.android.com/guide/topics/fundamentals/fragments.html#EventCallbacks
You should use onActivityCreated to set the values.
Set references in onCreateView and then set values to them in onActivityCreated.
I am building a tablet app. In this app there is one activity with two fragments. First fragment is a "known" list fragment which is showing a simple one item layout list from a database query, the second fragment shows the details about the selected record (from the list fragment). The think with the second fragment is that its type depends from the records being showed in the list. For example if the records are customers then the selected customer's details are shown, if they are inventory items the selected item's details are shown etc.
In order to communicate with the Details Fragment I've created an interface which every detail fragment class implements.
The list fragment is "fixed" in the activity from the layout xml. The detail fragment however is created during the activity's creation like this:
super.onCreate(savedInstanceState);
setContentView(R.layout.act_hlpfiles_host);
...
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.laydetailsfragment, FragmentsPool.getHelperFileFragment(501), "recordDetails");
fragmentTransaction.commit();
myDetailsFragment = getFragmentManager().findFragmentByTag("recordDetails");
...
myListFragment = (frg_hlpfiles_lstrecords) getFragmentManager().findFragmentById(R.id.frg_lstrecords);
....
}
The problem with this code is that myDetailsFragment is always null. This is because the fragmentTransaction.commit() does not run immediately but it happens on the main thread the next time that thread is ready (as the android documentation states).
If I create the detail fragment in onStart() and instantiate the list fragment in onCreate everything works ok.
So the question is: How can I be sure that the fragmentTransaction.commit() has commit the transaction so I can do some work with the added fragment? Furthermore is there any way to wait until the commit happens and then continue with the rest of the code?
Try running fragmentManager.executePendingTransactions() after committing your transaction but before finding by tag and see if that works for you.
In Android API 24 FragmentTransaction has synchronous .commitNow() method.
It's in the reference now: https://developer.android.com/reference/android/app/FragmentTransaction.html#commitNow()
On the contrary, .commit() works asynchronously. It just schedules a commit of the transaction.
I was facing a similar issue.
I think the key learning here is using commitNow() instead of commit() with getSupportFragmentManager. This will disallow the main thread from executing until the fragment has been destroyed. It is imperative when building interfaces and using a shared activity. I should know it had me stumped for a while!
Here is a sample code example:
getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentById(R.id.fragment_frame)).commitNow();
"....so I can do some work with the added fragment? Furthermore is there any way to wait until the commit happens and then continue with the rest of the code?"
It all depends on what work you want to do. From your question I see that most of your work code should be in your fragment code anyway, for example when an inventory item is selected.
On the callback when a selection list item is selected (in order to change the details fragment) you'll be able to get hold of the details fragment comfortably enough anyway.
Furthermore, you already have the fragment from the return of FragmentsPool.getHelperFileFragment(501), so I don't see why you need to get the fragment via its tag.
I'm interested to know what work you need to do in onCreate with your added details fragment.