ViewPager+Fragment研究总结

viewpager+fragment在日常的开发中经常用到,viewpager为了提高用户进行左右切换时的流畅度,实现了一套预加载的功能,在默认情况下,viewpager会预加载一个页面(默认情况下为1,可以自己设置),即当你使用viewpager+fragment时,除了当前可见的第一个fragment会被加载之外,这个fragment后面的一个fragment也会被加载,这样用户进行切屏时就会更为流畅。但是在一些特殊情况下,我们可能不需要预加载的功能,我们更希望当fragment对用户可见时才进行加载或者是网络请求或者是特殊的操作(友盟统计页面访问情况等)。

这次的预期效果就是当fragment对用户可见时才进行网络请求,其中网络请求是通过AsyncTask实现的延迟操作。先看下效果图。
这里写图片描述

具体实现很简单,主要是通过fragment中setUserVisibleHint(boolean isVisibleToUser)方法进行当前fragment是否可见的判断。只有当此时的fragment对用户可见并且已经被创建才进行网络请求。在网络请求成功后加一个标示,防止来回切pagerview时进行重复的网络请求。下面看下源码。

public class MyFragment extends Fragment {
    private boolean isVisible = false;//fragment 可见标示
    private boolean isCreated = false;//fragment 已经被加载标示
    private boolean hasLoaded = false;//fragment 已做过网络请求标示

    private String contentStr;
    private TextView content;
    private  LinearLayout layout;

    public static final String KEY = "FRAGMENT_KEY";

    private String TAG = "fragment";

    public static MyFragment newInstance(String content) {//初始化fragment
        MyFragment fragment = new MyFragment();
        Bundle bundle = new Bundle();
        bundle.putString(KEY, content);
        fragment.setArguments(bundle);
        return fragment;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if(layout==null){
            layout = (LinearLayout) inflater.inflate(R.layout.fragment, container, false);
            content = (TextView) layout.findViewById(R.id.content);
            Bundle bundle = getArguments();
            if (bundle != null) {
                contentStr = bundle.getString(KEY);
            }
            isCreated = true;
            loading(" in onCreateView ");

            Log.v(TAG, contentStr + "   isCreated   ");
            return layout;
        }else{
            Log.v(TAG, contentStr + "   layout != null   ");
            return layout;
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        if (isVisibleToUser) {
            isVisible = true;
        } else {
            isVisible = false;
        }

        loading(" in setUserVisibleHint ");
    }


    private void loading(String str) {
        if (hasLoaded) {
            return;
        }

        if (isCreated && isVisible) {//可见并且已经被创建时,做网络请求
            UIHelper.showDialogForLoading(getActivity(), "正在加载...", true);

            Log.v(TAG, contentStr + str + "--->loading ");

            new AsyncTask<Void, Void, Boolean>() {

                @Override
                protected Boolean doInBackground(Void... params) {
                    try {
                        Thread.sleep(2000);
                    } catch (Exception e) {
                        e.printStackTrace();
                        return false;
                    }
                    return true;
                }

                @Override
                protected void onPostExecute(Boolean aBoolean) {
                    if (aBoolean) {
                        hasLoaded = true;
                        content.setText(contentStr);
                        UIHelper.hideDialogForLoading();
                    }
                }
            }.execute();
        }
    }
}

我们在关键的地方打一下log,看下loading方法是在oncreatView中执行还是在setUserVisibleHint中执行。

在再看下MainActivity的源码。

public class MainActivity extends AppCompatActivity {
    private ViewPager viewPager;
    private ArrayList<MyFragment> fragments=new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        viewPager= (ViewPager) findViewById(R.id.view_pager);
        fragments.add(MyFragment.newInstance("first fragment"));
        fragments.add(MyFragment.newInstance("second fragment"));
        fragments.add(MyFragment.newInstance("third fragment"));

        MyFragmentAdapter adapter=new MyFragmentAdapter(getSupportFragmentManager(),fragments);
        viewPager.setAdapter(adapter);
    }

    class MyFragmentAdapter extends FragmentPagerAdapter{
        private ArrayList<MyFragment> fragments;

        public MyFragmentAdapter(FragmentManager fm,ArrayList<MyFragment> fragments) {
            super(fm);
            this.fragments=fragments;
        }

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

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

}

下面看下log。这是第一次运行时的log。

first fragment in onCreateView --->loading
first fragment    isCreated
second fragment   isCreated

因为viewPager在默认情况下,会预加载一个页面。(可以通过setOffscreenPageLimit设置预加载页面数)。所以当只是第一个fragment对用户可见时,第二个fragment已经被加载好了。并且第一个fragment是在onCreateView 中执行的loading方法,原因是此时setUserVisibleHint方法在onCreateView 之前调用但是此时isCreated为false所以无法执行网络请求。

下面切到到第二个fragment,此时的log。

second fragment in setUserVisibleHint --->loading
third fragment   isCreated

此时第二个fragment因为已经被加载好了,并且在setUserVisibleHint方法中得知以为可见状态,所以执行了loading方法。于此同时第三个fragemnt也已经被加载。下面切到第三个fragment。

third fragment in setUserVisibleHint --->loading

与之前同理,因为此前第三个fragment已经被加载,而且此时对用户可见,可以执行loading方法。

最后贴一下工具类的代码。

public class UIHelper {

private static Dialog mLoadingDialog;


public static void showDialogForLoading(Activity context, String msg, boolean cancelable) {
    if(context==null){
        return;
    }
    View view = LayoutInflater.from(context).inflate(R.layout.loading_dialog, null);
    TextView loadingText = (TextView)view.findViewById(R.id.dialog_content);
    loadingText.setText(msg);

    mLoadingDialog = new Dialog(context, R.style.loading_dialog_style);
    mLoadingDialog.setCancelable(cancelable);
    mLoadingDialog.setContentView(view, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
    mLoadingDialog.show();
}

public static void hideDialogForLoading() {
    if(mLoadingDialog != null && mLoadingDialog.isShowing()) {
        mLoadingDialog.cancel();
    }
}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值