Reputation: 373
I am confused by Fragment managers and fragments. In the book "Android Programming" by big nerd ranch, they instantiate a fragment in the MainActivity.
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if (fragment == null) {
fragment = new CrimeFragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, fragment)
.commit();
}
In the second line, they find the fragment not by the ID of the fragment, but by the ID of the fragmentContainer. FragmentContainer is just a plain layout. The book says that "[the container view ID] is used as a unique identifier for a fragment in the FragmentManager's list.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
On a different page, when coding this fragmentContainer, they write "You can and will use this same layout to host other fragments."
If this layout can host other fragments, how can this layout be used as a unique identifier for a fragment in the FragmentManager's list? Why don't they do
fm.findFragmentById(R.id.[some fragment id here])
and instead using the Id of a fragment container that that can host other fragments as well?
Upvotes: 1
Views: 2526
Reputation: 10421
they find the fragment not by the ID of the fragment, but by the ID of the fragmentContainer.
The cool thing is that the Fragment ID and the Fragment Container ID are the same thing! Update your code to add some logging statements:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crime);
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragment_container);
if (fragment != null) {
Log.d(TAG, "fragment id: " + fragment.getId());
}
View fragmentContainer = findViewById(R.id.fragment_container);
Log.d(TAG, "fragment container id: " + fragmentContainer.getId());
if (fragment == null) {
fragment = new CrimeFragment();
fm.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit();
}
}
Then run the app and rotate the device:
CrimeActivity: fragment container id: 2131296335
DEVICE ROTATION
CrimeActivity: fragment id: 2131296335
CrimeActivity: fragment container id: 2131296335
Obviously, your ID will be different than mine.
When you create the FragmentTransaction
fm.beginTransaction().add(R.id.fragmentContainer, fragment)
the FragmentManager will use the ID as both a way to identify this fragment from the list of fragments that it is managing and as the location in the view hierarchy to display the fragment.
On a different page, when coding this fragmentContainer, they write "You can and will use this same layout to host other fragments."
If this layout can host other fragments, how can this layout be used as a unique identifier for a fragment in the FragmentManager's list?
That last sentence should be clarified to read
"You can and will use this same layout to host other fragments, by replacing the current fragment with a different one."
There will only ever be one fragment with that ID and only one spot in the view hierarchy with that id. Jump ahead to code listing 17.8 (in the second edition) to see a replacement example.
if (findViewById(R.id.detail_fragment_container) == null) {
Intent intent = CrimePagerActivity.newIntent(this, crime.getId());
startActivity(intent);
} else {
Fragment newDetail = CrimeFragment.newInstance(crime.getId());
getSupportFragmentManager().beginTransaction()
.replace(R.id.detail_fragment_container, newDetail)
.commit();
}
The replace call with throw way whatever Fragment was currently in detail_fragment_container
and insert newDetail
fragment, setting it's ID to R.id.detail_fragment_container
.
One comment suggested:
I would use tags: .add(R.id.fragmentContainer, fragment, "MY TAG") and then: findFragmentById("MY TAG")
This doesn't directly solve the problem. Now you have two ways to identify a Fragment: it's Tag and it's ID (a Fragment will still be given an ID just by the fact that you are adding it to R.id.fragment_container
).
Given two ways to identify the Fragment, it will be up to you as a developer to keep track of what is displayed where. Which Fragment is this (what is it's TAG) and where is it being displayed (what is it's ID)?
Upvotes: 2
Reputation: 24998
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. This first searches through fragments that are currently added to the manager's activity; if no such fragment is found, then all fragments currently on the back stack associated with this ID are searched.
That's the docs for findFragmentById( )
. If the fragment was inflated from XML using the fragment
tag, then it will do exactly as you said. If it was added dynamically by using a transaction, it'll look for fragments with the associated container ID.
Upvotes: 0