2

I am building an app with 3 tabs on the root view. I want to include swipe to change tab function so I am using the support framework and the FragmentPagerAdapter as suggested in Android training documentation. My first two tabs were built without a problem using custom adapters. However when I added a third tab using ArrayAdapter, changing between tabs more than twice generates IllegalStateException.

04-17 17:17:13.792: E/AndroidRuntime(2158): FATAL EXCEPTION: main
04-17 17:17:13.792: E/AndroidRuntime(2158): java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.view.ViewGroup.addViewInner(ViewGroup.java:3509)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.view.ViewGroup.addView(ViewGroup.java:3380)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.view.ViewGroup.addView(ViewGroup.java:3325)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.view.ViewGroup.addView(ViewGroup.java:3301)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.support.v4.app.NoSaveStateFrameLayout.wrap(NoSaveStateFrameLayout.java:40)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:931)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.support.v4.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1280)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:672)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1467)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:472)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.support.v4.view.ViewPager.populate(ViewPager.java:1068)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.support.v4.view.ViewPager.populate(ViewPager.java:914)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.support.v4.view.ViewPager$3.run(ViewPager.java:244)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.view.Choreographer.doCallbacks(Choreographer.java:562)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.view.Choreographer.doFrame(Choreographer.java:531)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.os.Handler.handleCallback(Handler.java:730)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.os.Handler.dispatchMessage(Handler.java:92)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.os.Looper.loop(Looper.java:137)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at android.app.ActivityThread.main(ActivityThread.java:5103)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at java.lang.reflect.Method.invokeNative(Native Method)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at java.lang.reflect.Method.invoke(Method.java:525)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
04-17 17:17:13.792: E/AndroidRuntime(2158):     at dalvik.system.NativeStart.main(Native Method)

As you can see it's none of my code, just Android library code. Anybody has any idea on how to fix it? I've been trying out everything I found on this forum but nothing worked for me yet.

public class PreciousTrackerPagerAdapter extends FragmentPagerAdapter {

public static final int TAB_COUNT = 3;
public static final int TAB_PRECIOUS_MOVES = 0;
public static final int TAB_PRECIOUS_ITEMS = 1;
public static final int TAB_PRECIOUS_CATEGORY = 2;

private PreciousMovesFragment movesFragment;
private PreciousItemsFragment itemsFragment;
private PreciousCategoryFragment categoryFragment;

public PreciousTrackerPagerAdapter(FragmentManager fm) {
    super(fm);
}

@Override
public Fragment getItem(int index) {
    switch (index) {
    case TAB_PRECIOUS_MOVES:
        if (movesFragment == null) {
            movesFragment = new PreciousMovesFragment();
        }
        return movesFragment;
    case TAB_PRECIOUS_ITEMS:
        if (itemsFragment == null) {
            itemsFragment = new PreciousItemsFragment();
        }
        return itemsFragment;
    case TAB_PRECIOUS_CATEGORY:
        if (categoryFragment == null) {
            categoryFragment = new PreciousCategoryFragment();
        }
        return categoryFragment;
    default:
        return null;
    }
}

@Override
public int getCount() {
    return TAB_COUNT;
}


}

The fragment that I added to the third tab that seemed to cause the problem here.

public class PreciousCategoryFragment extends Fragment {

private List<PreciousCategory> categoryList;
private View rootView;

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);

    if (rootView == null) {
        rootView = inflater.inflate(R.layout.category_list, null);
    }

    return rootView;
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    refreshList();
}

private void refreshList() {
    PreciousTrackerModel model = PreciousTrackerModel.getInstance(getActivity());
    categoryList = model.getCategoryList();
    ArrayAdapter<PreciousCategory> adapter = new ArrayAdapter<PreciousCategory>(getActivity(), android.R.layout.simple_list_item_1, categoryList);
    ListView listView = (ListView) getActivity().findViewById(R.id.lstCategory);
    listView.setAdapter(adapter);
}

}

And how I added the tabs in the main activity. Each tab takes the entire content space.

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

    setContentView(R.layout.activity_main);
    model = PreciousTrackerModel.getInstance(this);

    pagerAdapter = new PreciousTrackerPagerAdapter(getSupportFragmentManager());
    viewPager = (ViewPager) findViewById(R.id.pager);
    viewPager.setAdapter(pagerAdapter);
    viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
        public void onPageSelected(int position) {
            // When swiping between pages, select the
            // corresponding tab.
            getActionBar().setSelectedNavigationItem(position);
        }
    });

    // enable tabs in action bar
    final ActionBar actionBar = getActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    // add tabs with listener
    actionBar.addTab(actionBar.newTab().setText(R.string.moves).setTabListener(this));
    actionBar.addTab(actionBar.newTab().setText(R.string.items).setTabListener(this));
    actionBar.addTab(actionBar.newTab().setText(R.string.category).setTabListener(this));
}
2
  • I doubt this code is causing that exception. Still, if I were you I'll start removing the check inside onCreateView. Also in refresh() list you are looking for the ListView inside the Activity. Probably it belongs to category_list.xml, so you should use getView instead of getActivity Commented Apr 17, 2014 at 7:48
  • You were right about it, too, man. Thanks for your help. Commented Apr 17, 2014 at 9:44

2 Answers 2

2

I think that PreciousCategoryFragment::onCreateView is your problem.

It should look like this:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_messages, null, false);
}
Sign up to request clarification or add additional context in comments.

1 Comment

That did it! Still wondering why 2 tabs were no problem but not important any more.
1

You are asking why this happen only when you have 3 or more tabs and not when you have 2 tabs.

This because when you have 2 tabs they are initialized whit onCreateView and onResume right to the start of the activity! And they aren't called anymore if you switch tabs!

Because when you go on a tab, Android load the adjacents! And so trigger on onCreateView, onResume, etc.. But if you have 2 tabs they will be always adjacent!

Now if you have 3 tabs the third one isn't loaded right away! It will load when you switch to it or to the second, that is adjacent!

The reason because android do that is simple. if the next one isn't ready, it couldn't do the "swipe effect"!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.