1

The Problem:

I am trying to create two tabs containing Fragments with a FragmentTabHost.

Here is where I add the tabs to the FragmentTabHost (the onCreate method of the FragmentActivity that contains the tabs:

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_financials);

    mTabHost = (FragmentTabHost) findViewById(R.id.tabhost);
    mTabHost.setup(this, getSupportFragmentManager(), android.R.id.tabcontent);

    mTabHost.addTab(
            mTabHost.newTabSpec(TAG_ONE).setIndicator("Tab #1",
                    getResources().getDrawable(android.R.drawable.star_on)),
                    MyFragmentOne.class, null);
    mTabHost.addTab(
            mTabHost.newTabSpec(TAG_TWO).setIndicator("Tab #2",
                    getResources().getDrawable(android.R.drawable.star_on)),
                    MyFragmentTwo.class, null);


    if(savedInstanceState == null) {
        new MyAsyncTask(MyClass.this).execute();    
    }
    else {
        mTabHost.setCurrentTabByTag(savedInstanceState.getString("TAB_TAG"));
    }

}

However, the problem is that both MyFragmentOne and MyFragmentTwo are waiting for data from MyAsyncTask. That is, the views in each fragment can only be created properly after MyAsyncTask has completed running.

So I end up getting a NullPointerException when I add the tabs because the required data hasn't been fetched by the AsyncTask yet.

My Solution Attempt:

I tried calling TabHost#addTab() in the onPostExecute() of MyAsyncTask so that the Fragments are only created after MyAsyncTask completes, thus avoiding any null pointers.

However, by moving the addTab() calls to onPostExecute() of the AsyncTask, I get the error: No tab tag for null. Logcat below.

Logcat:

08-06 06:15:17.947: E/AndroidRuntime(1968): java.lang.IllegalStateException: No tab known for tag null
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.support.v4.app.FragmentTabHost.doTabChanged(FragmentTabHost.java:330)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.support.v4.app.FragmentTabHost.onAttachedToWindow(FragmentTabHost.java:280)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.View.dispatchAttachedToWindow(View.java:12585)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2458)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2465)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2465)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2465)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2465)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2465)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1217)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5670)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.Choreographer.doCallbacks(Choreographer.java:574)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.Choreographer.doFrame(Choreographer.java:544)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.os.Handler.handleCallback(Handler.java:733)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.os.Handler.dispatchMessage(Handler.java:95)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.os.Looper.loop(Looper.java:136)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at android.app.ActivityThread.main(ActivityThread.java:5017)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at java.lang.reflect.Method.invokeNative(Native Method)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at java.lang.reflect.Method.invoke(Method.java:515)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
08-06 06:15:17.947: E/AndroidRuntime(1968):     at dalvik.system.NativeStart.main(Native Method)

So how can I solve this problem?

u3l
  • 3,342
  • 4
  • 34
  • 51

2 Answers2

1

I ended up using a blank PlaceHolderFragment and removing them programmatically in onPostExecute() like so:

mTabHost.addTab(
            mTabHost.newTabSpec("Placeholder one").setIndicator("Tab #1",
                    getResources().getDrawable(android.R.drawable.star_on)),
                    PlaceHolderFragment.class, null);
mTabHost.addTab(
            mTabHost.newTabSpec("Placeholder two").setIndicator("Tab #2",
                    getResources().getDrawable(android.R.drawable.star_on)),
                    PlaceHolderFragment.class, null);

Then in onPostExecute() :

mTabHost.setCurrentTab(0);
mTabHost.clearAllTabs();

mTabHost.addTab(
        mTabHost.newTabSpec(TAG_ONE).setIndicator("Tab #1",
                getResources().getDrawable(android.R.drawable.star_on)),
                MyFragmentOne.class, null);
mTabHost.addTab(
        mTabHost.newTabSpec(TAG_TWO).setIndicator("Tab #2",
                getResources().getDrawable(android.R.drawable.star_on)),
                MyFragmentTwo.class, null);
u3l
  • 3,342
  • 4
  • 34
  • 51
  • Sorry but I don't see any logic to your solution/ logcat error. Anyway congrats!! :) – mromer Aug 06 '14 at 13:15
  • Since it seems that I MUST add tabs in `onCreateView`, I add two dummy tabs that are empty. If I don't do this, then I get an `IllegalStateException`. Then, in my `AsyncTask`, once I fetch the required data from the server, it calls `onPostExecute()`, which removes the dummy tabs that contain blank Fragments, and adds the two tabs I need to put there. This way I get no `NullPointerException` either since the data has already been fetched by the `AsyncTask`. – u3l Aug 06 '14 at 13:19
  • it looks like this is the only possible solution if you really need to lazy load your tabHost content. You actually don't need to add two dummy tabs, one is enough but it looks like the tabHost can't be empty after the view is returned from onCreateView – vanomart Mar 31 '16 at 13:10
0

You can create an AsyncTaks with a callback. Then in that callback you can create your tabs with the data.

For example: android asynctask sending callbacks to ui

This is just an example, there are a lot of examples using asyncTask and callbacks

Community
  • 1
  • 1
mromer
  • 1,867
  • 1
  • 13
  • 18
  • A callback would still result in the same no tab tag for null error since it is essentially the same as having the asynchronous task nested in the fragment activity and implementing it's onpostexecute. (I tried using a callback earlier and got the same error) – u3l Aug 06 '14 at 11:15
  • Ok, you are right. Did you try to create the tabs with some dummy data? – mromer Aug 06 '14 at 11:50
  • Yeah, actually I tried just that and it worked great, i'll post it as an answer. – u3l Aug 06 '14 at 13:08