前言

1.Fragment+ViewPager一块使用的时候,其实懒加载是ViewPager中就有的,看过ViewPager源码的人都知道,ViewPager中有设置默认的懒加载的页数,默认的是1,但是这个1可不是我们通常说的一页,这个1而是左右各一页的意思。

比如:有四个模块分别为:推荐、地图、服务、我的四个模块。 (1)分别为0、1、2、3四个位置,当我们点击“推荐”的时候,按左右各一页原理,要加载“推荐”左边的(没有不加载)和右边的“地图”两个模块。 (2)当我们点击“服务”模块的时候,要加载的是左边一页“地图”和右边一页“我的”两个模块。

其中解决方法: (1)第一种方式就是把源码里面的Viewpager类里面的代码全部复制出来到自定义的一个类里面把默认值改为0即可。 (2)第二种方式是在Fragment中重写setUserVisibleHint()方法实现Fragment中的懒加载模式。

主要是介绍第二种方式解决懒加载问题。

1.解析

我们在做应用开发的时候,一个Activity里面可能会以Viewpager(或其他容器)与多个Fragment来组合使用,而如果每个Fragment都需要去加载数据,或从本地加载,或从网络加载,那么在这个Activity刚创建的时候就变成需要初始化大量资源。这样的结果,我们当然不会满意。那么,能不能做到当切换到这个Fragment的时候,它才去初始化呢?

2.使用原理

其实答案就在Fragment的setUserVisibleHint这个方法里,当Fragment执行的时候,系统会默认调用该方法,会告诉系统Fragment的UI是否可见。

3.使用方式

所以我们只需要继承Fragment并重写该方法,即可实现在fragment可见时才进行数据加载操作,即Fragment的懒加载。

代码如下:

package com.zhjy.hxf.hzfragment.fragment;

import android.support.v4.app.Fragment;

/**
 * @author :huangxianfeng on 2017/2/9.
 * 封装Fragment的数据缓加载
 */
public abstract class BaseFragment extends Fragment {

    /**
     *  Fragment是否可见
     */
    protected boolean isVisible;

    /**
     * 在这里实现Fragment数据的缓加载
     * 此方法会告诉Fragment的UI是否可见
     * 当可见的时候,再去加载数据
     * @param isVisibleToUser
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (getUserVisibleHint()){
            /**
             * Fragment可见时
             */
            isVisible = true;
            onVisible();
        }else{
            /**
             * Fragment不可见时
             * 不可见的时候可以做一些初始化之前的准备工作
             */
            isVisible =false;
            onInvisible();
        }
    }

    /**
     * 可见的时候执行的此方法
     */
    protected void onVisible(){
        load();   
    }

    /**
     * 子类实现load()方法实现一些缓加载数据
     */
    protected abstract void load();

    /**
     * 不可见的时候执行的此方法
     */
    protected void onInvisible(){}
}

**4.BaseFragment **

在BaseFragment ,我增加了三个方法,一个是onVisiable,即fragment被设置为可见时调用,一个是onInvisible,即fragment被设置为不可见时调用。另外再写了一个load的抽象方法,该方法在onVisible里面调用。你可能会想,为什么不在getUserVisibleHint里面就直接调用呢?

在fragment中,我们还需要创建视图(onCreateView()方法),可能还需要在它不可见时就进行其他小量的初始化操作(比如初始化需要通过AIDL调用的远程服务)等。而setUserVisibleHint是在onCreateView之前调用的,那么在视图未初始化的时候,在load当中就使用的话,就会有空指针的异常。而把load抽离成一个方法。

LeftFragment 代码如下:

package com.zhjy.hxf.hzfragment.fragment;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.zhjy.hxf.hzfragment.R;

/**
 * @author :huangxianfeng on 2017/2/9.
 * 当显示RightFragment是的时候,LeftFragment是不可见的,
 * 此时不会执行load()方法,而是会执行onInVisible()方法。
 * 执行不可见时的方法。
 */
public class LeftFragment extends BaseFragment {

    /**
     * 标志位,标志已经初始化完成
     */
    private boolean isPrepared;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.e("Log_TAG", "Left onCreateView");
        View view = View.inflate(getContext(), R.layout.fragment_left,null);
        isPrepared = true;
        load();
        return view;
    }

    @Override
    protected void load() {
        Log.e("Log_TAG", "LeftFragment isPrepared = "+isPrepared);
        Log.e("Log_TAG", "LeftFragment isVisible = "+isVisible);
        /**
         * 不可见或者未初始化完成的时候直接返回,不做任何事情
         */
        if (!isPrepared || !isVisible){
            return;
        }
        System.out.println("Left可见并控件初始化完成");
    }

    /**
     * 当此类不可见时,会执行此方法
     */
    @Override
    protected void onInvisible() {
        super.onInvisible();
        System.out.println("Left--不可见");
    }
}

RightFragment 代码如下:

package com.zhjy.hxf.hzfragment.fragment;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.zhjy.hxf.hzfragment.R;

/**
 * @author :huangxianfeng on 2017/2/9.
 * 当显示LeftFragment是的时候,RightFragment是不可见的,
 * 此时不会执行load()方法,而是会执行onInVisible()方法。
 * 执行不可见时的方法。
 */
public class RightFragment extends BaseFragment{

    /**
     * 标志位,标志已经初始化完成
     */
    private boolean isPrepared;


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.e("Log_TAG","Right onCreateView");
        View view = View.inflate(getContext(), R.layout.fragment_right,null);
        isPrepared = true;
        load();
        return view;
    }

    @Override
    protected void load() {
        Log.e("Log_TAG", "RightFragment isPrepared = "+isPrepared);
        Log.e("Log_TAG", "RightFragment isVisible = "+isVisible);
        if (!isPrepared || !isVisible){
            return;
        }
        System.out.println("Right可见并控件初始化完成");
    }

    /**
     * 当此类不可见的时候,会执行此方法。
     */
    @Override
    protected void onInvisible() {
        super.onInvisible();
        System.out.println("Right--不可见");
    }
}

在上面的类当中,我们增加了一个标志位isPrepared,用于标志是否初始化完成。然后在我们所需要的初始化操作完成之后调用,如上面的例子当中,在初始化view之后,设置 isPrepared为true,同时调用lazyLoad()方法。而在lazyLoad()当中,判断isPrepared和isVisible只要有一个不为true就不往下执行。也就是仅当初始化完成,并且可见的时候才继续加载,这样的避免了未初始化完成就使用而带来的问题。

其他类代码:

MainActivity

package com.zhjy.hxf.hzfragment.activity;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import .AppCompatActivity;
import android.support.v7.widget.Toolbar;

import com.zhjy.hxf.hzfragment.R;
import com.zhjy.hxf.hzfragment.adapter.ViewPagerAdapter;
import com.zhjy.hxf.hzfragment.fragment.LeftFragment;
import com.zhjy.hxf.hzfragment.fragment.RightFragment;

import java.util.ArrayList;

/**
 * @author :huangxianfeng on 2017/2/9.
 * 主界面类
 */
public class MainActivity extends AppCompatActivity {
    private ViewPager mViewPager;
    private LeftFragment mLeftFragment;
    private RightFragment mRightFragment;
    private ArrayList<Fragment> mArrayList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(.toolbar);
        setSupportActionBar(toolbar);

        initView();

    }

    private void initView() {
        if (mArrayList == null){
            mArrayList = new ArrayList<>();
        }
        if (mLeftFragment == null){
            mLeftFragment = new LeftFragment();
        }
        if (mRightFragment == null){
            mRightFragment = new RightFragment();
        }
        mViewPager = (ViewPager)findViewById(.viewpager);
        mArrayList.add(mLeftFragment);
        mArrayList.add(mRightFragment);

        ViewPagerAdapter pagerAdapter = new ViewPagerAdapter(getSupportFragmentManager(),mArrayList);
        mViewPager.setAdapter(pagerAdapter);
    }
}

ViewPagerAdapter代码:

/**
 * @author :huangxianfeng on 2017/2/9.
 */
public class ViewPagerAdapter extends FragmentPagerAdapter {

    private ArrayList<Fragment> mArrayList;

    public ViewPagerAdapter(FragmentManager fm, ArrayList<Fragment> mArrayList) {
        super(fm);
        this.mArrayList = mArrayList;
    }

    @Override
    public Fragment getItem(int position) {
        return mArrayList.get(position);
    }

    @Override
    public int getCount() {
        return mArrayList.size();
    }
}