Open source, coffee and us….

Archives

Android TabHost fun

My initial impressions were that using a TabActivity to divide the task in hand up would be a good idea, and would be realtively straightforward, but as in all things once you start getting into the detail, little things crop up that cause you no end of consternation and grief.

Firstly, the documentation for View based tabs rather than Intent driven tabs is a little sparse, and in this instance I had no need to sub-divide things in that way. However, for straightforward XML based views, all works well. For detailed views it is worth separating each tab out into their own layout files, e.g.

<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/tabhost"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
 
    <TabWidget android:id="@android:id/tabs"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
    </TabWidget>
 
    <FrameLayout android:id="@android:id/tabcontent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >
 
        <include layout="@layout/tab1" />
        <include layout="@layout/tab2"/>
        <include layout="@layout/tab3"/>
        <include layout="@layout/tab4"/>
        <include layout="@layout/tab5"/>
    </FrameLayout>
</TabHost>

The view can then be set up in the onCreate method, adding the tabs as necessary using the layout ids for each page.

This was all well and good until I decided what I wanted to do was have dynamic tabs, where certain tabs were only present if certain data items existed, and as the user could add or remove those data items, then the tabs needed to change on demand.

The logical solution is to build and rebuild the tabs during onResume. This of course leads to the first issue, which is that there is no removeTab method, so we have to use clearAllTabs and rebuild all tabs, including those which are effectively static. This reveals a slight shortcoming inside the Android code, whereby if the user was not on the first tab when clearAllTabs was called, then a NullPointerException is thrown.  The simple answer is to execute setCurrentTab(0) before clearAllTabs, but this also has interesting side effects, more of which later.

The next issue was that unlike when executed in the onCreate method, the creation of each TabSpec caused a RuntimeException as a result of not finding the layout view when using tabSpec.setContent(R.layout.tab1) for example. This was eventually solved by implementing a TabContentFactory and using that as the tabContent, e.g.

class TabFactory implements TabContentFactory {
 
@Override
   public View createTabContent(String tabName) {
 
        View v = null;
        int viewId = 0;
        if (TAB1.equals(tabName)) {
            viewId = R.layout.tab1;
        } else if (TAB2.equals(tabName)) {
            viewId = R.layout.tab2;
        } else if (TAB3.equals(tabName)){
            viewId = R.layout.tab3;
        } else {
            viewId = R.layout.tabx;
        }
        v = findViewById(viewId);
        if (v == null) {
            v = getLayoutInflater().inflate(viewId, null);
        }
        return v;
    }
 
}

This way of creating the tab content allows for the views to be inflated if necessary. The example shows a single Factory for creating multiple contents, but for more complex cases more specialised ones may be used to simplify the logic.

The next issue was to understand how the tabs are processed, and the events that occur. When the content is added to the TabHost, the tab content is created by the factory, and an internal setCurrentPage(0) is executed, resulting in the firing of the onTabChanged event, which will by default resolve the contained View. This event does not happen for subsequent additional tabs, which is sensible as you do not need to populate other views until the user wishes to see the chosen tab. Thus, the only realistic/simple way of populating the tabs is to do so using an OnTabChangeListener, which can react to the movement of the user and set up any Views accordingly.

This is where things get a little awkward for dynamic tabs, as a result of the forced setCurrentTab(0) prior to clearAllTabs. This means that the onTabChanged event is fired and any set-up performed by the TabChangeListener will be invoked. When clearAllTabs is subsequently executed, any physical views registered with the TabHost are removed, so any views saved as fields within the activity are now not linked at all. One solution for this is to make sure that any fields saved are nullified between clearAllTabs and the rebuilding of the tabs.

There is probably a lot more to look out for, but that may be covered at another time.

Cheap Pills in International Sites

Cheap Pharmacyaccutane canada buy in Europe

Cheap PharmacyBuy Online doxycycline

Online

OnlineCanadian Pharmacy No Prescription

Order

Cheapbuy antibiotics no prescription

PurchaseDrugs no Prescription EUROPE
or herebuy viagra UKbuy propecia ukviagra australia and you can see more here australia pharmacy generic