Fragment for lazy loading

Posted by thientanchuong on Sun, 05 May 2019 21:16:03 +0200

1.

 

1. When we do application development, a single Activity may be combined with multiple fragments by viewpager (or other containers). ViewPager caches three pages of data by default.

 

2. That is, every Fragment loaded by Viewpager, the Fragment on the left or right side of the Fragment is preloaded.

 

3. If every fragment needs to load data, either locally or from the network, then when this activity was created, it would become necessary to initialize a large number of resources, waste user traffic, and cause Katon. Of course, we would not be satisfied with the result. So, can it be initialized when switching to this fragment? The answer lies in the method of setUserVisibleHint in Fragment.

 

 

2. setUserVisibleHint()

 

1. This method is used to tell the system whether the UI of the Fragment is visible. So we only need to inherit fragments and rewrite this method to implement data loading operation when fragments are visible, that is, lazy loading of fragments.

 

2. Many people on the Internet recommend that the operation of loading data be put in this function. In this way, if only the network data acquisition is possible, but if other operations are done, it is not possible. For example:

First: If you also need to do something when Fragment is "visible - > invisible", such as canceling the display of the load control.

Second: If you have Fragment s visible, you need to manipulate some controls, such as displaying load controls.

 

2.1, reasons:

 

A. When FragemntA enters FragmentB from a FragemntA, FragmentB types false first and then true, because setUserVisibleHint() is called once when Fragment is instantiated, and the default value is false, and it will be called again when the currently displayed Fragment is selected.

 

SetUserVisibleHint () may be called outside of Fragment's lifetime, that is, before view is created, or after destroyView, so null exceptions may be reported if some control operations are involved because the control has not been initialized or destroyed.

 

 

 

Third, package lazy loading

 

1. Load network data in onFragmentFirstVisible(), which will execute after onCreateView(), indicating the first entry into the Fragment.

 

2. onFragment VisibleChange (), is Fragment visible

@Override

protected void onFragmentVisibleChange(boolean isVisible) {

    super.onFragmentVisibleChange(isVisible);

    logE("Fragment1111111_Home Visible----" + isVisible);

}

3. Complete code

/**
 *
 * http://www.cnblogs.com/dasusu/p/6745032.html
 * Viewpager + Fragment In the case of fragments, the lifetime of fragments loses its concrete meaning due to the caching mechanism of Viewpager
 * So, we construct a new callback method in Fragment's life cycle
 * Lazy Fragment can be inherited when lazy loading is required
 */

public abstract class LazyFragment extends BaseFragment {
    private static final String TAG = "LazyFragment==";

    private boolean isFragmentVisible;
    private boolean isReuseView;
    private boolean isFirstVisible;
    private View rootView;

    //setUserVisibleHint() is called once when Fragment is created and passed in isVisibleToUser = false
    //If the current Fragment is visible, setUserVisibleHint() will be called again, passing in isVisibleToUser = true
    //If Fragment is visible - > invisible, setUserVisibleHint() will also be invoked, passing in isVisibleToUser = false
    //Summary: setUserVisibleHint() is called back when the visible state of Fragment changes, and also when new Fragment().
    //If we need to do something when Fragment s are visible or invisible, then there will be redundant callbacks, so we need to re-encapsulate one.
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
       // logE( "setUserVisibleHint==" + isVisibleToUser + " rootView==" + rootView);
        //setUserVisibleHint() may be invoked outside the fragment lifetime
        if (rootView == null) {
            return;
        }
        if (isFirstVisible && isVisibleToUser) {
            onFragmentFirstVisible();
            isFirstVisible = false;
        }
        if (isVisibleToUser) {
            onFragmentVisibleChange(true);
            isFragmentVisible = true;
            return;
        }
        if (isFragmentVisible) {
            isFragmentVisible = false;
            onFragmentVisibleChange(false);
        }
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initVariable();
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        //If setUserVisibleHint() is called before the rootView is created, then
        //Callback onFragmentVisibleChange(true) after the rootView is created
        //Ensure that the callback to onFragmentVisibleChange() occurs after the rootView is created to support ui operations

       // logE( "onViewCreated rootView==" + rootView);
        if (rootView == null) {
            rootView = view;
            if (getUserVisibleHint()) {
                if (isFirstVisible) {
                    onFragmentFirstVisible();
                    isFirstVisible = false;
                }
                onFragmentVisibleChange(true);
                isFragmentVisible = true;
            }
        }
        super.onViewCreated(isReuseView ? rootView : view, savedInstanceState);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        initVariable();
    }

    private void initVariable() {
        isFirstVisible = true;
        isFragmentVisible = false;
        rootView = null;
        isReuseView = true;
    }

    /**
     * Set whether to use view reuse, open by default
     * view Reuse means that onCreateView () - > onDestroyView () is constantly invoked by ViewPager when fragments are destroyed and rebuilt.
     * Life functions between them, which may lead to repeated creation of view s, resulting in multiple identical fragments on the interface
     * view In fact, reuse means saving the view created for the first time, and then returning directly to the view created for the first time when onCreateView()
     *
     * @param isReuse
     */
    protected void reuseView(boolean isReuse) {
        isReuseView = isReuse;
    }

    /**
     * Remove redundant callback scenarios from setUserVisibleHint() to ensure that callbacks occur only when the fragment visible state changes
     * The callback time is after view is created, so ui operations are supported to solve the problem that ui operations in setUserVisibleHint() may report null exceptions.
     * <p>
     * Some ui display and hiding can be done in this callback method, such as the display and hiding of loading box.
     *
     * @param isVisible true  Invisible - > visible
     *                  false Visible - > invisible
     */
    protected void onFragmentVisibleChange(boolean isVisible) {

    }

    /**
     * Callback when fragments are first visible, where data can be loaded to ensure that data is loaded only when fragments are first opened.
     * This prevents the data from being loaded repeatedly every time it enters.
     * This method is called before onFragmentVisibleChange(), so when it is first opened, a global variable can be used to represent the status of data download.
     * In this method, the state is set to download state, and then the download task is performed.
     * Finally, in onFragmentVisibleChange(), the display and hiding of download progress ui controls are controlled according to data download status.
     */
    protected abstract void onFragmentFirstVisible();

    protected boolean isFragmentVisible() {
        return isFragmentVisible;
    }

}

4, use.

public class Fragment2_Home extends LazyFragment{


    @Override
    protected void onFragmentFirstVisible() {
        //Perform network requests
    }

    @Override
    protected void onFragmentVisibleChange(boolean isVisible) {
        super.onFragmentVisibleChange(isVisible);
        logE("Fragment1111111_Home Visible----" + isVisible);
    }



}

 

Learn from:

Another Fragment lazy load (load only once)

One of the optimization schemes of ndroid--the lazy loading implementation of Fragment

Topics: Fragment network