ViewPager+Fragment研究总结

来源:互联网 发布:淘宝美工网上兼职 编辑:程序博客网 时间:2024/06/18 06:54

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 --->loadingfirst fragment    isCreatedsecond fragment   isCreated

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

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

second fragment in setUserVisibleHint --->loadingthird 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();    }}

}

0 0