Get Fragment dynamically attached to <FrameLayout>? - android

Well, i got a simple <FrameLayout>:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/FragmentContainer"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
Then in my code, i added a Fragment to it:
FragClass aFrag = new FragClass();
getSupportFragmentManager().beginTransaction()
.replace(R.id.FragmentContainer, aFrag).commit();
And somewhere else in my code, i want to get that FragClass (extends Fragment) object from the ID R.id.FragmentContainer.
i have tried
((ViewGroup) findViewById(R.id.FragmentContainer)).getChildAt(0)
or
((FrameLayout) findViewById(R.id.FragmentContainer)).getChildAt(0)
but they are returning the View, instead of the Fragment attached to it.
i know i can keep the variable aFrag somewhere, so i do not need to find it again. But i believe there should be a way to retieve it.

Let me wrap it up by a full answer :)
In this case, the dynamically added Fragment uses the ID of the container View (ViewGroup).
ref: http://developer.android.com/guide/components/fragments.html#Adding
Note: Each fragment requires a unique identifier that the system can use to restore the fragment if the activity is restarted (and which you can use to capture the fragment to perform transactions, such as remove it). There are three ways to provide an ID for a fragment:
Supply the android:id attribute with a unique ID.
Supply the android:tag attribute with a unique string.
If you provide neither of the previous two, the system uses the ID of the container view.
It is because it's a Fragment afterall. We have to use getSupportFragmentManager().findFragmentById() to retrieve it, which returns a Fragment, instead of findViewById() which returns a View.
So the answer to this problem would be:
((aFrag) getSupportFragmentManager().findFragmentById(R.id.FragmentContainer))
Thanks to #Luksprog.

Related

Android ChildFragmentManager().findFragmentById() always null

I stumbled into a crazy little 'bug', or i'm just doing something wrong. I am trying to get the reference to a fragment that is inside a fragment. So we have ParentFragment, that is a child of MainActivity. I can get a reference to this ParentFragment without a problem, because the ParentFragment is added to the MainActivity via code:
ParentFragment fragment = new ParentFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragmentPlaceholder, fragment);
transaction.commit();
I have added a ChildFragment to the ParentFragment via XML like this:
parent_fragment.xml
<RelativeLayout ... etc>
.. some other views, findViewById('') works great on these.
<fragment
android:layout_width="70dp"
android:layout_height="70dp"
android:id="#+id/childFragment1"
android:tag="1"
class="com.my.package.ChildFragment"
android:name="com.my.package.ChildFragment"
tools:layout="#layout/child_fragment" />
</RelativeLayout>
All works fine, the ChildFragment(s) show up in the ParentFragment. The only thing is; i cannot find the fragmentById.
I have tried multiple ways of achieving this, how it should be done (?) :
getChildFragmentManager().findFragmentById(R.id.childFragment1)
Didn't work. Also, getting the Activity and using that fragment manager doesn't work (.. of course).
I have also tried getting all fragments in the ChildFragmentManager, iterating over them etc. But this always returns null:
getChildFragmentManager().getFragments()
Do you have any idea why this is happening? Can't i use the ChildFragrentManager if the fragments are not added via code?
Thanks!
You must add your child fragment dynamically. See here:
Note: You cannot inflate a layout into a fragment when that layout
includes a <fragment>. Nested fragments are only supported when added
to a fragment dynamically.
ps. if you are planning to use nested fragments then be prepared for various strange behaviours, you can find them in bug reports to android platform:
https://code.google.com/p/android/issues/list?can=2&q=nested+fragment&sort=-opened&colspec=ID+Status+Priority+Owner+Summary+Stars+Reporter+Opened&cells=tiles
If you want to use nested Fragments and be able to get a reference to them via findFragmentById you cannot use the support package.
I changed all getSupportFragmentManager()'s to getFragmentManager() and replaced all FragmentActivity's with regular Activity's.
Now it works as expected, just call getChildFragmentManager().findFragmentById().

How can I get Fragment from View?

I added some Fragment into a TableLayout and I want to manage them from my container Activity, so I used this:
Fragment fragment = (Fragment) tableLayout.getChildAt(i);
but getChildAt(int) returns a View and a View could NOT cast to Fragment
I don't understand why people are down-voting your question. Fragments can be very confusing at times, especially for beginners. To understand your problem, you must learn what is a Fragment and how they are used.
To start with, a View is something that has an existence on the screen. Examples include: TextView, EditText, Button, etc. They are placed inside "layouts" written in Xml or Java/Kotlin. These layouts are shown using an Activity.
Now, a Fragment is not a View. It does not have any existence on the screen at all. Instead, it's a class that simply manages a "layout" — kinda similar to an Activity. If you need the View returned by your Fragment's onCreateView(), you can directly use findViewById() within your Activity.
If you need a reference to your Fragment, there are two possible ways of doing this:
1) If you added the Fragment programmatically like this
getFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container_viewgroup, myFragment, FRAGMENT_TAG)
.commit();
You can use:
MyFragment myFragment = (MyFragment) getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
2) If you added the Fragment inside an XML layout like this:
<fragment android:name="com.example.android.fragments.HeadlinesFragment"
android:id="#+id/fragmentContainer"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
You can use this:
getFragmentManager().findFragmentById(R.id.fragmentContainer);
Basically, each Activity has a FragmentManager class that maintains all the active Fragments, and there are two ways of finding them: Using a unique TAG that you pass while showing a fragment, or passing the container view-ID where the fragment was added.
For people looking how to actually get a reference to the Fragment object from a View there is now a method in FragmentManager called findFragment(View) (reference)
//in Java
FragmentManager.findFragment(view)
//in Kotlin there is an extension function
view.findFragment()
Be careful - it will throw an IllegalStateException if the view was not added via a fragments onCreateView.
You can not get a fragment like this. You will have to add fragment with a tag and retrieve it by that tag.
to add a fragment do following:
getFragmentManager().beginTransaction().add(R.id.container, fragment, "tagTofindFragment");
to get fragment:
fragment = getFragmentManager().findFragmentByTag("tagTofindFragment");
Here tagTofindFragment is that tag that should be unique among your fragments.

How to add a Fragment ID or Fragment tag for a fragment in a ViewPager [duplicate]

How can I set a Fragment's Id so that I can use getSupportFragmentManager().findFragmentById(R.id.--)?
You can't set a fragment's ID programmatically.
There is however, a String tag that you can set inside the FragmentTransaction which can be used to uniquely identify a Fragment.
As Aleksey pointed out, you can pass an ID to FragmentTransaction's add(int, Fragment) method. However, this does not specify the ID for a Fragment. It specifies the ID of a ViewGroup to insert the Fragment into. This is not that useful for the purpose I expect you have, because it does not uniquely identify Fragments, but ViewGroups. These IDs are of containers that one or more fragments can be added to dynamically. Using such a method to identify Fragments would require you to add ViewGroups dynamically to the Layout for every Fragment you insert. That would be pretty cumbersome.
So if your question is how to create a unique identifier for a Fragment you're adding dynamically, the answer is to use FragmentTransaction's add(int containerViewId, Fragment fragment, String tag) method and FragmentManager's findFragmentByTag(String) method.
In one of my apps, I was forced to generate strings dynamically. But it's not that expensive relative to the actual FragmentTransaction, anyway.
Another advantage to the tag method is that it can identify a Fragment that isn't being added to the UI. See FragmentTransaction's add(Fragment, String) method. Fragments need not have Views! They can also be used to persist ephemeral state between config changes!
Turns out you may not need to know the fragment id.
From the docs:
public abstract Fragment findFragmentById (int id)
Finds a fragment that was identified by the given id either
when inflated from XML or as the container ID when added in
a transaction.
The important part is "as the container ID when added in a transaction".
so:
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_holder, new AwesomeFragment())
.commit();
and then
AwesomeFragment awesome = (AwesomeFragment)
getSupportFragmentManager()
.findFragmentById(R.id.fragment_holder);
will get you whatever (awesome) fragment is held in R.id.fragment_holder.
In most cases you can use the fragment tag as well as the ID.
You can set the tag value in FragmentTransaction.add(Fragment fragment, String tag );.
Then you can use the command FragmentManager.findFragmentByTag(String tab) to find the fragment in question.
As Tom and others already mention, there are ways to put a tag on a fragment and use that tag for identification. A subsequent problem I've come across with those solutions is that the fragment doesn't get a tag until it's associated with the Activity (or, actually, the FragmentManager). What to do if one needs to identify a fragment before it has been tagged?
My solutions so far all rely on the oldest (Java) trick in the world: create a minimalistic template fragment which takes an id in one of it's constructors and provides a getFragmentId() method which returns that id. I then let those fragments that need early identification extend that template and; voila! Problem solved.
This solution might, unfortunately, require a set of template fragments, one for each fragment type, ListFragment, DialogFragment or plain old Fragment (POFO?!) that need early identification. But this is manageable in the case of fragments I think, considering the gains provided.
Sorry for tearing up healing wounds :-)
Cheers!
Use the following:
To add a fragment:
getFragmentManager().beginTransaction().add(R.id.fragment_container, fragmentToBeAdded, tag).commit();
To identify existing fragment:
getFragmentManager().findFragmentByTag(fragmentName);
When using a tag please do make sure to add the
fragmentTransaction.addToBackStack(null);
method 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.
I lost about 30 minutes trying to figure out why my Fragment was not being found through a simple findFragmentByTag(); call
In addition to Tom's answer, replace method also supports the fragment tag, in addition to add method.

Assigning ID to dynamically created ListFragment

I am currently working on this code for Android and it has a dynamically created listfragment. Even the listview is assigned to it dynamically. It takes a simple cursor object from SQL Lite and assigns it to an adapter.
It all works great, problem is when orientation changes happen, the savedInstanceState bundle is always null. Even if I override OnSaveInstanceState and add items to that bundle or onCreateView. I did some research and found out that this is happening because the fragment has no ID assigned to it.
I am having a little bit of a problem as to where to assign an ID to to the listfragment and how. I am using FragmentTransaction and using a TAG identifier.
I would appreciate any help on this matter.
Thank you.
Take a look at this question: Android - Set fragment id
You can't assign an ID to a dynamically created fragment.
You can, however, create an .xml layout file and assign an id to your fragment there with android:id="#+id/my_fragment". Is there a reason you are not using an xml-defined fragment?
You can do this while you do the transaction. If you call
FragmentTransaction.replace(containerViewId, fragment, tag);
OR
FragmentTransaction.add(fragment,tag)
OR
FragmentTransaction.add(containerViewId, fragment, tag);
You can then use the tag to get a reference to the Fragment like this
FragmentManager.findFragmentByTag(tag);

Android - Set fragment id

How can I set a Fragment's Id so that I can use getSupportFragmentManager().findFragmentById(R.id.--)?
You can't set a fragment's ID programmatically.
There is however, a String tag that you can set inside the FragmentTransaction which can be used to uniquely identify a Fragment.
As Aleksey pointed out, you can pass an ID to FragmentTransaction's add(int, Fragment) method. However, this does not specify the ID for a Fragment. It specifies the ID of a ViewGroup to insert the Fragment into. This is not that useful for the purpose I expect you have, because it does not uniquely identify Fragments, but ViewGroups. These IDs are of containers that one or more fragments can be added to dynamically. Using such a method to identify Fragments would require you to add ViewGroups dynamically to the Layout for every Fragment you insert. That would be pretty cumbersome.
So if your question is how to create a unique identifier for a Fragment you're adding dynamically, the answer is to use FragmentTransaction's add(int containerViewId, Fragment fragment, String tag) method and FragmentManager's findFragmentByTag(String) method.
In one of my apps, I was forced to generate strings dynamically. But it's not that expensive relative to the actual FragmentTransaction, anyway.
Another advantage to the tag method is that it can identify a Fragment that isn't being added to the UI. See FragmentTransaction's add(Fragment, String) method. Fragments need not have Views! They can also be used to persist ephemeral state between config changes!
Turns out you may not need to know the fragment id.
From the docs:
public abstract Fragment findFragmentById (int id)
Finds a fragment that was identified by the given id either
when inflated from XML or as the container ID when added in
a transaction.
The important part is "as the container ID when added in a transaction".
so:
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_holder, new AwesomeFragment())
.commit();
and then
AwesomeFragment awesome = (AwesomeFragment)
getSupportFragmentManager()
.findFragmentById(R.id.fragment_holder);
will get you whatever (awesome) fragment is held in R.id.fragment_holder.
In most cases you can use the fragment tag as well as the ID.
You can set the tag value in FragmentTransaction.add(Fragment fragment, String tag );.
Then you can use the command FragmentManager.findFragmentByTag(String tab) to find the fragment in question.
As Tom and others already mention, there are ways to put a tag on a fragment and use that tag for identification. A subsequent problem I've come across with those solutions is that the fragment doesn't get a tag until it's associated with the Activity (or, actually, the FragmentManager). What to do if one needs to identify a fragment before it has been tagged?
My solutions so far all rely on the oldest (Java) trick in the world: create a minimalistic template fragment which takes an id in one of it's constructors and provides a getFragmentId() method which returns that id. I then let those fragments that need early identification extend that template and; voila! Problem solved.
This solution might, unfortunately, require a set of template fragments, one for each fragment type, ListFragment, DialogFragment or plain old Fragment (POFO?!) that need early identification. But this is manageable in the case of fragments I think, considering the gains provided.
Sorry for tearing up healing wounds :-)
Cheers!
Use the following:
To add a fragment:
getFragmentManager().beginTransaction().add(R.id.fragment_container, fragmentToBeAdded, tag).commit();
To identify existing fragment:
getFragmentManager().findFragmentByTag(fragmentName);
When using a tag please do make sure to add the
fragmentTransaction.addToBackStack(null);
method 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.
I lost about 30 minutes trying to figure out why my Fragment was not being found through a simple findFragmentByTag(); call
In addition to Tom's answer, replace method also supports the fragment tag, in addition to add method.

Categories

Resources