Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android fragment oncreateview called on tab change

I've been working with Android for a while, but fragments are a little new to me (as they are to most people probably). Anyway, I've got the below code, and it works fine. I've got three fragments, one in each tab. I'm wondering if it's normal for onCreateView to be called everytime I switch tabs, and does it make sense to do so? Shouldn't there be a way to NOT redraw the fragment every time the tab changes?

I'm converting this from an app that had 3 activities, one in each tab, and it seems like a waste to recreate the view every time the tab changes, when it used to be just fine having the views exist between tab changes...

BTW, this code borrowed from: http://thepseudocoder.wordpress.com/2011/10/04/android-tabs-the-fragment-way/

public class Tabs extends FragmentActivity implements
    TabHost.OnTabChangeListener {

final String MAP_TAB = "Map";
final String IMAGES_TAB = "Images";
final String SETTINGS_TAB = "Settings";

TabHost mTabHost;
HashMap<String, TabInfo> mapTabInfo = new HashMap<String, TabInfo>();
TabInfo mLastTab = null;

private class TabInfo {
    private String tag;
    private Class clss;
    private Bundle args;
    private Fragment fragment;
    TabInfo(String tag, Class clazz, Bundle args) {
        this.tag = tag;
        this.clss = clazz;
        this.args = args;
    }

}

class TabFactory implements TabContentFactory {

    private final Context mContext;

    public TabFactory(Context context) {
        mContext = context;
    }

    public View createTabContent(String tag) {
        View v = new View(mContext);
        v.setMinimumWidth(0);
        v.setMinimumHeight(0);
        return v;
    }

}

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.main);

    initialiseTabHost(savedInstanceState);
    if (savedInstanceState != null)
        mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); //set the tab as per the saved state
}

protected void onSaveInstanceState(Bundle outState) {
    outState.putString("tab", mTabHost.getCurrentTabTag()); //save the tab selected
    super.onSaveInstanceState(outState);
}

private void initialiseTabHost(Bundle args) {
    mTabHost = (TabHost)findViewById(android.R.id.tabhost);
    mTabHost.setup();
    TabInfo tabInfo;

    Tabs.addTab(this,
            mTabHost,
            mTabHost.newTabSpec(MAP_TAB).setIndicator(
                    MAP_TAB,
                    getResources().getDrawable(R.drawable.ic_tab_map_states)),
            ( tabInfo = new TabInfo(MAP_TAB, HMapFragment_NEW.class, args)));
    mapTabInfo.put(tabInfo.tag, tabInfo);

    Tabs.addTab(this,
            mTabHost,
            mTabHost.newTabSpec(IMAGES_TAB).setIndicator(
                    IMAGES_TAB,
                    getResources().getDrawable(R.drawable.ic_tab_gallery_states)),
            ( tabInfo = new TabInfo(IMAGES_TAB, ImageGridFragment.class, args)));
    mapTabInfo.put(tabInfo.tag, tabInfo);

    Tabs.addTab(this,
            mTabHost,
            mTabHost.newTabSpec(SETTINGS_TAB).setIndicator(
                    SETTINGS_TAB,
                    getResources().getDrawable(R.drawable.ic_tab_settings_states)),
            ( tabInfo = new TabInfo(SETTINGS_TAB, SettingsFragment.class, args)));
    mapTabInfo.put(tabInfo.tag, tabInfo);

    // Default to first tab
    this.onTabChanged(MAP_TAB);
    mTabHost.setOnTabChangedListener(this);
}

private static void addTab(Tabs activity, TabHost tabHost, TabHost.TabSpec tabSpec, TabInfo tabInfo) {
    // Attach a Tab view factory to the spec
    tabSpec.setContent(activity.new TabFactory(activity));
    String tag = tabSpec.getTag();

    // Check to see if we already have a fragment for this tab, probably
    // from a previously saved state.  If so, deactivate it, because our
    // initial state is that a tab isn't shown.
    tabInfo.fragment = activity.getSupportFragmentManager().findFragmentByTag(tag);
    if (tabInfo.fragment != null && !tabInfo.fragment.isDetached()) {
        FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();
        ft.detach(tabInfo.fragment);
        ft.commit();
        activity.getSupportFragmentManager().executePendingTransactions();
    }

    tabHost.addTab(tabSpec);
}

public void onTabChanged(String tag) {
    TabInfo newTab = this.mapTabInfo.get(tag);
    // if they've clicked to change tabs
    if (mLastTab != newTab) {
        FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction();
        if (mLastTab != null)
            if (mLastTab.fragment != null) ft.detach(mLastTab.fragment);
        if (newTab != null) {
            if (newTab.fragment == null) {
                newTab.fragment = Fragment.instantiate(this, newTab.clss.getName(), newTab.args);
                ft.add(R.id.realtabcontent, newTab.fragment, newTab.tag);
            } else ft.attach(newTab.fragment);
        }

        mLastTab = newTab;
        ft.commit();
        this.getSupportFragmentManager().executePendingTransactions();
    }
}
}
like image 478
joshkendrick Avatar asked Jun 12 '12 19:06

joshkendrick


People also ask

How many times does Android fragment oncreateview call twice?

10 fragment onCreateView called many times 6 Android fragment OnCreateView called twice 9 NullPointerException due to 'void dalvik.system.CloseGuard.close()' in lollipop

Is oncreateview () actually called when fragment is on the screen?

So while debugging, I arrived to the conclusion that nothing works because onCreateView () is not actually called, even though my Fragment is on the screen. This happens after I rotated the device and I'm in landscape mode. If I report the device in portrait mode (from landscape to portrait again) and try to call that method, all is good.

Why doesn't onactivitycreated () work with fragments?

Exactly, that's why the onActivityCreated () method isn't called. You create the Fragments after the Activity has been created. So it wouldn't make sense to call that method. Maybe you could use onAttach () instead. Click to expand... I didn't follow your line of thought, could you please re-elaborate?

How to create swipeable tabs layout in Android?

Android Tabs with Fragments and ViewPager In android, we can create swipeable tabs layout using Swipe Views to switch between the tabs in the android application. The Swipe Views in android provides navigation between the sibling screens such as tabs with a horizontal finger gesture, sometimes it is called horizontal paging.


1 Answers

There a 3 ways to remove a Fragment from view:

  • Hide it (hide function on transaction object)
  • Detach it (detach function on transaction object)
  • Remove it (remove function on transaction object)

If you hide it the view gets hidden, but is still in the layout and should stay intact. If you detach it, the view gets torn down, but the fragment is still managed by the FragmentManager (and will be recreated on a configuration change, for example). If you remove it it gets removed from the FragmentManager completely and it's state will no longer be managed.

like image 118
Timo Ohr Avatar answered Sep 18 '22 23:09

Timo Ohr