I have a FragmentActivity that contains a Fragment. this fragment contains a FragmentTabHost. The tab host contains three tabs that each one is a ListFragment.
The lists are configured with custom adapter that getting updates from the main FragmentActivity, and calling notifyDatasetChanged on update.
My problem is that it seems the ListFragment UI never updates the view when it's shown. If I change tabs - I can see the list updates, but I can't see the updates on real time when a list is shown on the screen.
That's the definition of the Fragment containing the FragmentTabHost:
public class SubOptionFragmentManager extends Fragment
{
FragmentTabHost mTabHost;
SoiListFragment mFrag1;
SoiListFragment mFrag2;
SoiListFragment mFrag3;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.soi_container, container, false);
}
public void init(FragmentManager fm, int optionInstanceID)
{
mOptionInstanceID = optionInstanceID;
// find and setup the tabhost
mTabHost = (FragmentTabHost)getActivity().findViewById(android.R.id.tabhost);
mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.realtabcontent);
// add the three tabs
mTabHost.addTab(mTabHost.newTabSpec("1")
.setIndicator("1"),
SoiListFragment.class,
getTabBundle("1", optionInstanceID));
mTabHost.addTab(mTabHost.newTabSpec(dsTag)
.setIndicator("2"),
SoiListFragment.class,
getTabBundle("2", optionInstanceID));
mTabHost.addTab(mTabHost.newTabSpec("3")
.setIndicator("3"),
SoiListFragment.class,
getTabBundle("3", optionInstanceID));
// get reference to the fragments added
mFrag1 = (SoiListFragment)getChildFragmentManager().findFragmentByTag("1");
mFrag2 = (SoiListFragment)getChildFragmentManager().findFragmentByTag("2");
mFrag3 = (SoiListFragment)getChildFragmentManager().findFragmentByTag("3");
}
public void HandleSoiItemUpdate(SubOptionInstanceItem soi, int fragID)
{
Log.i(TAG, "ItemUpdate:" + soi.toString());
updateItemRunnable ur = new updateItemRunnable(soi, int fragID);
getActivity().runOnUiThread(ur);
}
class updateItemRunnable implements Runnable
{
SubOptionInstanceItem mItem;
int mFragID;
public updateItemRunnable (SubOptionInstanceItem item, int fragID)
{
mItem = item;
}
public void run()
{
switch (mFragID)
{
// the second parameter - true means it calls notifyDatasetChanged() after updating the item
case 1:
mFrag1.getAdapter().updateItem(mItem, true);
break;
case 2:
mFrag2.getAdapter().updateItem(mItem, true);
break;
case 3:
mFrag3.getAdapter().updateItem(mItem, true);
break;
}
}
}
}
Also included in that class is the ListFragment object:
public static class SoiListFragment extends ListFragment
{
private int mOptionInstanceID;
private int mPageType;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mOptionInstanceID = getArguments().getInt(FIELD_OPTION_INSTANCE_ID);
mPageType = getArguments().getInt(FIELD_PAGE_TYPE);
}
public SubOptionInstanceAdapter getAdapter()
{
return (SubOptionInstanceAdapter)getListAdapter();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// inflate the list view and return it
View v = inflater.inflate(R.layout.soi_list, container, false);
init();
return v;
}
public void init()
{
SubOptionInstanceAdapter mAdapter = null;
switch(mPageType)
{
case 1:
mAdapter = new SubOptionInstanceAdapter(getActivity(),
R.layout.soi_item,
Globals.getList1());
break;
case 2:
mAdapter = new SubOptionInstanceAdapter(getActivity(),
R.layout.soi_item,
Globals.getList2());
break;
case 3:
mAdapter = new SubOptionInstanceAdapter(getActivity(), R.layout.soi_item, Globals.getList3());
break;
}
setListAdapter(mAdapter);
}
The fragment layout "soi_container.xml" (simple layout containing FragmentTabHost):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/background" >
<android.support.v4.app.FragmentTabHost
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0" />
</android.support.v4.app.FragmentTabHost>
<FrameLayout
android:id="@+id/realtabcontent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
My first problem was the init()
placement on the onCreateView
part.
That caused the init()
to occur each time a tab was loaded or changed - that's why I thought that the tab is being updated only when not visible.
Also, getting the ListFragments reference on init()
in the container was wrong, as the fragments were not created yet on that point.
Finally my solution was to create the tabs on the container fragment during the OnStart
event, getting the list fragment reference and initialize them with adapter in the onTabCreated
event then updating them using the reference I got before.
EDIT: code sample for Ravi - getting the list fragment reference
public void onTabCreated(int pageType)
{
// if I don't already have the reference for the fragment
if (mFrag1 == null)
{
mFrag1 = (SoiListFragment)getFragmentManager().findFragmentByTag("1");
}
}