u3l
u3l

Reputation: 3412

FragmentTabHost and Asynchronous Tasks

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?

Upvotes: 1

Views: 558

Answers (2)

u3l
u3l

Reputation: 3412

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);

Upvotes: 1

mromer
mromer

Reputation: 1897

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

Upvotes: 0

Related Questions