Rewrite FragmentTabHost to avoid creating content page Fragments again during navigation bar switching

Keywords: Fragment Android Java

Problem Description: In the previous article, we used onActivityCreated (...) for each fragment in the navigation bar. This method prints a toast and displays the toast dialog box when repeatedly switching pages. This means that each content page fragment is recreated when switching. It is expected that the first entry is created, and then the switch entry is no longer created.

Solution: If I had used radioGroup+FrameLayout to implement the navigation bar before, I would have encountered the above situation at that time. At that time, my idea was to solve the problem. When I create a new content page fragment, I save it and give it a tag. Next time I switch to this page, I search the tag field to see if it has been created. If it has been created, I take it out and display it directly. If not, I create and add tags. In fact, the idea of rewriting FragmentTabHost implementation is the same, because the principle of FragmentTabHost+FrameLayout implementation is similar to that of radioGroup+FrameLayout. Let's look at a method of FragmentTabHost, which is the key to solving the problem. The code is as follows:

private FragmentTransaction doTabChanged(String tabId, FragmentTransaction ft) {
        TabInfo newTab = null;
        for (int i=0; i<mTabs.size(); i++) {
            TabInfo tab = mTabs.get(i);
            if (tab.tag.equals(tabId)) {
                newTab = tab;
            }
        }
        if (newTab == null) {
            throw new IllegalStateException("No tab known for tag " + tabId);
        }
        if (mLastTab != newTab) {
            if (ft == null) {
                ft = mFragmentManager.beginTransaction();
            }
            if (mLastTab != null) {
                if (mLastTab.fragment != null) {
                    ft.detach(mLastTab.fragment);
                }
            }
            if (newTab != null) {
                if (newTab.fragment == null) {
                    newTab.fragment = Fragment.instantiate(mContext,
                            newTab.clss.getName(), newTab.args);
                    ft.add(mContainerId, newTab.fragment, newTab.tag);
                } else {
                    ft.attach(newTab.fragment);
                }
            }

            mLastTab = newTab;
        }
        return ft;
    }

Focusing on ft.detach(mLastTab.fragment) and ft.attach(newTab.fragment), I will first explain several methods of Fragment Transaction:
(1) attach(Fragment fragment) method, which means that if the previous fragment is separated from the UI through detach(Fragment fragment), it will be recreated and displayed.
(2) detach(Fragment fragment) means that if you separate from the UI, you remove it from the UI and destroy it.
(3) hide(Fragment fragment) the main meaning: hide Fragment, do not destroy.
(4) show(Fragment fragment): Show hidden fragments.

After looking at the four methods above, it should be clear what FragmentTabHost recreates Fragments when switching, in combination with the content of doTabChanged(). The main reason is the use of ft.detach(mLastTab.fragment) and ft.attach(newTab.fragment). If we replace these two methods with hide and show, we can solve the problem. Operational process, copy FragmentTabHost under android.support.v4.app package to the folder of our custom control, such as: I put it in the widget folder of my project, and then modify the doTabChanged() method. The modification code is as follows:

private FragmentTransaction doTabChanged(String tabId, FragmentTransaction ft) {
        TabInfo newTab = null;
        for (int i=0; i<mTabs.size(); i++) {
            TabInfo tab = mTabs.get(i);
            if (tab.tag.equals(tabId)) {
                newTab = tab;
            }
        }
        if (newTab == null) {
            throw new IllegalStateException("No tab known for tag " + tabId);
        }
        if (mLastTab != newTab) {
            if (ft == null) {
                ft = mFragmentManager.beginTransaction();
            }
            if (mLastTab != null) {
                if (mLastTab.fragment != null) {
                    // Replace detach with hide to hide Fragment
                    // ft.detach(mLastTab.fragment);
                    ft.hide(mLastTab.fragment);
                }
            }
            if (newTab != null) {
                if (newTab.fragment == null) {
                    newTab.fragment = Fragment.instantiate(mContext,
                            newTab.clss.getName(), newTab.args);
                    ft.add(mContainerId, newTab.fragment, newTab.tag);
                } else {
                    // Replace attach with show to display Fragment
                    // ft.attach(newTab.fragment);
                    ft.show(newTab.fragment);
                }
            }

            mLastTab = newTab;
        }
        return ft;
    }

Finally, change the android.support.v4.app.FragmentTabHost used in the layout to the FragmentTabHost rewritten by itself. For example, I changed it to com. lyl. weeklearning. widget. FragmentTabHost. Also, in the java file using FragmentTabHost, modify the import package, such as my modification: import com.lyl.weeklearning.widget.FragmentTabHost; at this point, the article is over, there is something wrong with it, you are welcome to comment and correct.^^

Posted by Draicone on Tue, 09 Apr 2019 18:48:32 -0700