3

I've noticed that there are numerous issues with using tabhost, but none of them really fit my issue. I am trying to create a view with an action bar on top, then a row of tabs under the bar. Here's my activity layout.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    style="@style/Dashboard">

    <com.ftni.common.ui.ActionBar
        android:id="@+id/actionbar"
        style="@style/ActionBar"/>

    <TabHost android:id="@android:id/tabhost"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:padding="5dp">
            <TabWidget
                android:id="@android:id/tabs"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />
            <FrameLayout
                android:id="@android:id/tabcontent"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:padding="5dp" />
        </LinearLayout>
    </TabHost>
</LinearLayout>

Next, we have my activity declared as such

public class DashboardActivity extends TabActivity {

and I am building my tabs like this.

private void buildTabs()
{
    Resources res = getResources(); // Resource object to get Drawables
    TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost);  // The activity TabHost
    TabHost.TabSpec spec;  // Resusable TabSpec for each tab
    Intent intent;  // Reusable Intent for each tab

    // Create an Intent to launch an Activity for the tab (to be reused)
    intent = new Intent().setClass(this, StatementsActivity.class);

    // Initialize a TabSpec for each tab and add it to the TabHost
    spec = tabHost.newTabSpec("statements").setIndicator("Statements",
                      res.getDrawable(R.drawable.ic_tab_active))
                  .setContent(intent);
    tabHost.addTab(spec);

    // Do the same for the other tabs
    intent = new Intent().setClass(this, PaymentsActivity.class);
    spec = tabHost.newTabSpec("payments").setIndicator("Payments",
                      res.getDrawable(R.drawable.ic_tab_active))
                  .setContent(intent);
    tabHost.addTab(spec);

    tabHost.setCurrentTab(0);
}

when I tried using getTabHost(); it was always returning a null. So, I switched to TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost); which does not return a null tabhost, but tabHost.addTab(spec); still causes a null pointer exception.

And here is the stacktrace

04-26 19:50:12.494: ERROR/AndroidRuntime(7367): FATAL EXCEPTION: main
04-26 19:50:12.494: ERROR/AndroidRuntime(7367): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ftni.consumer/com.ftni.consumer.ui.DashboardActivity}: java.lang.NullPointerException
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1622)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1638)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at android.app.ActivityThread.access$1500(ActivityThread.java:117)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:928)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at android.os.Handler.dispatchMessage(Handler.java:99)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at android.os.Looper.loop(Looper.java:123)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at android.app.ActivityThread.main(ActivityThread.java:3647)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at java.lang.reflect.Method.invokeNative(Native Method)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at java.lang.reflect.Method.invoke(Method.java:507)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at dalvik.system.NativeStart.main(Native Method)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367): Caused by: java.lang.NullPointerException
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at android.widget.TabHost.addTab(TabHost.java:212)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at com.ftni.consumer.ui.DashboardActivity.buildTabs(DashboardActivity.java:75)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at com.ftni.consumer.ui.DashboardActivity.onCreate(DashboardActivity.java:29)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1586)
04-26 19:50:12.494: ERROR/AndroidRuntime(7367):     ... 11 more

Line 75 is the first tabHost.addTab(spec);

Also, all my activities are declared in my manifest.

<activity android:name=".ui.DashboardActivity"></activity>
<activity android:name=".ui.StatementsActivity"></activity>
<activity android:name=".ui.PaymentsActivity"></activity>

EDIT:

Just to prove it isn't an issue, I removed the actionbar, put the layout to exactly what is in the tutorial, and I still get a null returned from getTabHost();

EDIT 2: full class code for clarity

public class DashboardActivity extends TabActivity {
    private ProfileModel profile;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        profile = Controller.getProfile();

        setContentView(R.layout.dashboard);

        buildTabs();

        new LoadDashboardTask().execute();
    }

    @Override
    public void onContentChanged()
    {
        ActionBar actionBar = (ActionBar)findViewById(R.id.actionbar);
        if (actionBar != null)
        {
            actionBar.setOnTitleClickListener(new OnClickListener() {
                public void onClick(View v) {
                    //do nothing for now.  User is already "home"
                }
            });

            if(profile.Accounts.length == 1)
                actionBar.setTitle(profile.Accounts[0].Name);
            else
                actionBar.setTitle(profile.Name);

        }
    }

    private void buildTabs()
    {
        Resources res = getResources(); // Resource object to get Drawables
        TabHost tabHost = getTabHost();// The activity TabHost

        if(tabHost != null)
        {
            // Initialize a TabSpec for each tab and add it to the TabHost
            TabSpec statementSpec = tabHost.newTabSpec("statements").setIndicator("Statements",
                              res.getDrawable(R.drawable.ic_tabs_statements))
                          .setContent(new Intent().setClass(DashboardActivity.this, StatementsActivity.class));
            tabHost.addTab(statementSpec);

            TabSpec paymentSpec = tabHost.newTabSpec("payments").setIndicator("Payments",
                              res.getDrawable(R.drawable.ic_tabs_payments))
                          .setContent(new Intent().setClass(DashboardActivity.this, PaymentsActivity.class));
            tabHost.addTab(paymentSpec);

            tabHost.setCurrentTab(0);
        }
    }

    private class LoadDashboardTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected void onPreExecute()
        {
            ActionBar actionBar = (ActionBar)findViewById(R.id.actionbar);
            actionBar.setProgressBarVisibility(View.VISIBLE);
        }

        @Override
        protected Void doInBackground(Void... params) 
        {
            return null;
        }

        @Override
        protected void onPostExecute(Void result)
        {
            ActionBar actionBar = (ActionBar)findViewById(R.id.actionbar);
            actionBar.setProgressBarVisibility(View.GONE);
        }
    }
}
Josh
  • 16,286
  • 25
  • 113
  • 158

1 Answers1

6

The documentation states that you should "Call setup() before adding tabs if loading TabHost using findViewById().", which is what you're doing. See here . However, since you're using a TabActivity, why are you not calling getTabHost() instead of getting the view manually?

dmon
  • 30,048
  • 8
  • 87
  • 96
  • In the OP I said when I call `getTabHost()` a null is returned. – Josh Apr 26 '11 at 20:13
  • BTW, I tried your suggestion of using setup, which then errored saying I needed to use an activity manager because I wasn't inheriting from TabActivity (which I am), which then errored with `Activities cannot be added until the containing group has been created`. It is almost like the whole thing is ignoring the fact that my activity is extended from TabActivity. – Josh Apr 26 '11 at 20:32
  • I've implemented tabs before without extending from TabActivity, so that's doable. Also, the docs state that the TabHost has to be the first element in the layout, which might be another problem (don't worry, it won't render anything before your action bar). When are you calling buildTabs, at what point of the onCreate? – dmon Apr 26 '11 at 20:47
  • I posted my entire class above. I tried changing the layout to be only the tabhost (and removing all the actionbar code) and still have problems with it. – Josh Apr 26 '11 at 20:58
  • I just wanted to point out that following the steps in the tutorial, I created the other activities with a text view, I added the state-list drawables, and I even tested the two activities that are in the tabs to be sure they work; they do. There is just something fundamentally wrong with my DashboardActivity class to the point that it's as if it is ignoring the TabActivity inheritance. Even when I put in my null checks and make the tab host the first item in the layout, I still get null reference exceptions from within the TabActivity class. – Josh Apr 26 '11 at 21:34
  • Weird. I'm out of ideas though, sorry. – dmon Apr 26 '11 at 22:03
  • If you're using Activities in your tab, you need to call setup(LocalActivityManager), not setup(). – Jules Jun 08 '12 at 16:09