LayoutInflater is a a really powerful tool that does really cool things; such as inflate a Fragment from a layout resource and properly handle its life-cycle. For example:
<fragment class="com.test.TestFrag".../>
when taking the above layout and running it through the LayoutInflater, you will get the view that is spawned by Fragment. You can then add this view to any ViewGroup and have an instance of a fragment running around that still follows the Fragment life-cycle. My question is, how do you get the parent Fragment from this created view?
There really is no mechanism, at run-time, for a fragment to know what ViewGroup is hosting it. That said, since your class would be extending the base Fragment class, there's nothing to stop you from adding an instance variable to your Fragment to keep track of the ID of it's parent. If your fragment is added into the view hierarchy with a FragmentTransaction, then you have to specify which container would host it, since FragmentTransaction::add requires the ID of the ViewGroup that will contain the fragment. If you're adding it to the ViewHierarchy using the XML tag, I don't see why you need to determine its parent at run-time since it isn't being added dynamically anyways.
Related
I know onCreateView inflates the View of a fragment, but why does it also return the View?
What is the returned View ever used for?
The Fragment Manager of the activity the fragment is hosted by calls all fragment lifecycle methods, so does this mean the Fragment Manager uses the returned View from onCreateView? If so, how?
What is the returned View ever used for?
It is used to allow the framework to display that portion of the UI. Otherwise, those widgets would be created, then ignored.
so does this mean the Fragment Manager uses the returned View from onCreateView?
Yes.
If so, how?
The fragment system calls addView() on the ViewGroup that will contain the view managed by the fragment.
What is the difference between
getActivity().findViewById(...)
and
View view = inflater.inflate(R.layout.fragment_fragment_v, null);
view.findViewById(...)
in Fragment (when converting Activity to Fragment)?
The difference is that with getActivty.findViewById(...) you are finding views in the scope of activity (activity's layout). With iflater.inflate(R.layout.fragment_fragment_v, null); view.findViewById(...) you are inflating the layout of your fragment and then finding view's in that layout.
But since your fragment is attached to the activity, you will find the view bothways, but I suggest you are finding view's for your fragment in your fragment's scope since there may be several fragments that have common layouts meaning there may be several view's associated with the same ID and that makes the getActivity().findBiewById(...) method unreliable
When you call findViewById with getActivity() you are telling Android to find the View within the Activity's layout, since Fragments are hosted inside Activities it will return you the correct View if its in the hierarchy.
By calling findViewById with the inflated View or in fact the getView() method provided by the framework you are essentially telling Android to find that View within the Fragment's view hierarchy, this should be your preferred approach as the findViewById algorithm will have to look for your View from a lesser set of View's and hence the search will be faster.
I'll leave you with this explanation about getView() from the developer docs.
getView()
Get the root view for the fragment's layout (the one returned by onCreateView(LayoutInflater, ViewGroup, Bundle)), if provided.
According to the android developer guide,
To get started, your layout must include a ViewGroup in which you
place each Fragment associated with a tab. Be sure the ViewGroup has a
resource ID so you can reference it from your tab-swapping code.
Alternatively, if the tab content will fill the activity layout
(excluding the action bar), then your activity doesn't need a layout
at all (you don't even need to call setContentView()). Instead, you
can place each fragment in the default root ViewGroup, which you can
refer to with the android.R.id.content ID (you can see this ID used in
the sample code below, during fragment transactions).
But without the setContentView(), whenever I call getActionBar(), it returns null. I am wondering how would I place fragment in the default root ViewGroup? Do I add it through XML or programmatically?
But without the setContentView(), whenever I call getActionBar(), it
returns null
On what Android versions did you test that? If I remember right this do happens on the 11 and 12 API levels but on other versions it works.
To avoid complication you should just set the content view to a layout with a simple FrameLayout and use that as the container for your fragments. You could also try just using Window.FLAG_ACTION_BAR without a content view:
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
You can add your fragment to default viewgroup which has id android.R.id.content. You don't need to layout your activity using setContentView() to do this.
mFragmentTransaction.add(android.R.id.content, mFragment, mTag);
I need to update a fragment with a different views.
As I figured out, to force Fragment::onCreateView() method call (to show my updates to the user) I can only use FragmentTransaction's method replace(, ).
It works good if I create a new Fragment and a new view for returning it from onCreateView() method every time I call FragmentTransaction::replace().
But I wish to keep some views in memory.
How can I reuse my views?
The problem is that if I use my view (that was attached to already replaced fragment) at a new fragment, I get an exception:
"java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first."
So, I try to detach the view from fragment by calling FragmentTransaction.detach() or FragmentTransaction.remove() to cause removing fragment from the activity and my view from already replaced fragment, but it doesn't help.
Does anybody know how to force a fragment to remove its child view (that was returned inside onCreateView()?
You're better off keeping the view contained within the Fragment so the Fragment itself handles it appropriately. Either have viewless Fragments send data to that Fragment to update the View or build the View with the parameters. It's cleaner and in the long run, much more maintainable.
Check out the Adding a Fragment without UI section.
The description of container parameter for function onCreateView of fragment class says :
container : If non-null, this is the parent view that the fragment's UI should be attached to. The fragment should not add the view itself, but this can be used to generate the LayoutParams of the view.
does the line
The fragment should not add the view itself, but this can be used to generate the LayoutParams of the view
mean that container.addView(some_view) is not permitted?
Correct. You would use this parameter in a call to inflate() on a LayoutInflater (e.g., inflater.inflate(R.layout.frag, container, false);) or to determine what LayoutParams are needed if you are creating your fragment contents directly via Java instead of inflation. Otherwise, the container is owned by the hosting activity, and your fragment should leave it alone, AFAIK.