Reputation: 13761
I'm working on a TabHost
whose tabs have associated a Fragment
(each tab a different one). Each of those Fragment
s have inside an instance of another Fragment
which is a login bar that has two states: Logged in or not.
Logged out example
Logged in example
In layout terms, each of these states have associated a View
(a TextView
for the non-logged-in case and a LinearLayout
for the logged-in case), so if one of them is VISIBLE
, the other one is GONE
. As per the tab content, this is an example of the code of one of them (firsttab.xml
):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ads="http://schemas.android.com/apk/lib/com.google.android.gms.ads"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0000FF"
android:orientation="vertical">
<!-- That's the login bar -->
<fragment
android:id="@+id/firsttab_loginrow"
class="com.mydomain.myproject.LoginRowFragment"
android:tag="1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:id="@+id/firsttab_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:orientation="horizontal">
</LinearLayout>
</LinearLayout>
The inner Fragment (com.mydomain.myproject.LoginRowFragment
) is defined this way:
<!-- If the user is not logged in -->
<TextView
android:id="@+id/identification_nologin"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textColor="#FFFFFF" />
<!-- if the user is logged in -->
<LinearLayout
android:id="@+id/identification_didlogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
...
</LinearLayout>
A general schema would be something like this:
The problem comes when I'm handling the tab change event by either attach()
ing or detach()
ing the correspondent parent Fragment
(in this case, firsttab.xml
). Previously to attaching/detaching the parent, I try detach()
ing the login Fragment
(the inner one), but it doesn't fire the onDetach()
callback. The same happens when attach()
ing. The weird thing is that if I replace .detach()
with .remove()
, it works just fine.
@Override
public void onTabChanged(final String tag) {
final TabInfo newTab = mTabInfo.get(tag);
if (lastTab != newTab) {
final FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction();
if ((lastTab != null) && (lastTab.getFragment() != null)) {
// This is where it fails detaching. tabInfo is just a structure where I store some data
// about the tabs to handle them. If I use remove() instead of the next detach() on loginFrag,
// the onAttach()/onDetach() callbacks are not called. I'm quite sure everything is ok, loginFrag
// is not null, it's actually the Fragment that should be detached, etc.
final Fragment loginFrag = (Fragment) lastTab.getFragment().getActivity().getSupportFragmentManager().findFragmentById(lastTab.getLoginFragId());
ft.detach(loginFrag);
ft.detach(lastTab.getFragment());
}
if (newTab != null) {
if (newTab.getFragment() == null) {
final TabFragmentInflater tabInf = new TabFragmentInflater();
newTab.setFragment(Fragment.instantiate(this, tabInf.getClass().getName(), newTab.getArgs()));
ft.add(R.id.realtabcontent, newTab.getFragment(), newTab.getTag());
}
else
ft.attach(newTab.getFragment());
}
ft.commit();
this.getSupportFragmentManager().executePendingTransactions();
lastTab = newTab;
}
}
So the question is the following:
Why onAttach()
/onDetach()
callbacks are not fired in the LoginRowFragment
class when using .attach()
or .detach()
on them, but get fired if I use .add()
or .remove()
respectively?
Upvotes: 2
Views: 3485
Reputation: 27236
You cannot remove an instance of a Fragment which has been declared in your layout XML file (by design)
When you use FragmentTransactions, you're manipulating ViewGroups containing the layout of a Fragment.
When you declare your Fragment/Class in a layout, it's part of the View hierarchy, so you can't remove it.
You can, however, add a New Fragment into that layout, because it will act as a container.
Try changing your Layout from:
<fragment
android:id="@+id/firsttab_loginrow"
class="com.mydomain.myproject.LoginRowFragment"
android:tag="1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
to:
<FrameLayout
android:id="@+id/firsttab_loginrow"
android:tag="1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
And create a FragmentTransaction
to add/replace/show/hide according to what you want to do.
Upvotes: 4