ViewPager+Fragment刷新更新Fragment

需求如下:顶部UI(这里随便写的),一些标签(服务器给的,这里写死),切换标签展示不同内容,内容分页展示,要求可以下拉刷新(重要页面,没刷新太low了吧),刷新之后还停在当前标签下面,但是内容也要刷新,切换内容也会如此。(插插更健康:github源码有ScrollableLayout三段式悬浮布局,相同需求)。demo效果如下:

ViewPager+Fragment刷新更新Fragment_第1张图片

需求分析:看上去很简单的一个页面,但是做起来不一定那么顺畅,看我一步步分析。选用的控件毫无疑问是SwipeRefreshLayout+TabLayout+ViewPager+Fragment+FragmentStatePagerAdapter 。

        分析1:由于标签数量length不确定(比较多),Fragment有预加载机制,如果使用默认的setOffscreenPageLimit提前加载下一个fragment,切换的时候导致看过的fragment被销毁/detach,再重新切换回去的话又得重新加载页面,请求api,体验很不好。如果使用setOffscreenPageLimit(length)预加载所有的fragment,更浪费资源,也不合理。所以需要使用Fragment的懒加载了,具体实现看后面的代码。

        分析2:为什么不用FragmentPagerAdapter而是用FragmentStatePagerAdapter?

        FragmentPagerAdapter类内的每一个生成的 Fragment 都将保存在内存之中,因此适用于那些相对静态的页,数量也比较少的那种。Fragment在切换的时候,不会销毁,而只是调用事务中的detach方法,我们只会把我们的Fragment的view销毁,而保留了以前的Fragment对象。所以通过这种方式创建的Fragment一直不会被销毁。

         FragmentSatetePagerAdapter 的实现将只保留当前页面,当页面离开视线后,就会被消除,仅保留状态信息,释放其资源;而在页面需要显示时,恢复状态信息,这样更节省内存。

        综上,根据需求选定FragmentStatePagerAdapter!

代码实现:

fragment懒加载基类:

import android.support.v4.app.Fragment;

/**
 * Created by zrg on 2018/1/2.
 * Fragment的懒加载模式
 * 使用方法:
 * ***** 必须继承 FragmentPagerAdapter/FragmentStatePagerAdapter,才可以对setUserVisibleHint()调用
 * setUserVisibleHint() 设置Fragment的可见状态
 * getUserVisibleHint() 获取Fragment的可见状态
 * mIsVisible 是父类的成员变量,子类不需要重写
 * mIsprepared 子类需要在OnCreateView()中重写
 * mHasLoadedOnce 子类需要在lazyLoad()中重写
 * 

* 接入步骤: * 1:继承BaseLazyFragment,实现lazyLoad() * 2:在onCreateView()中,添加以下代码: * mIsprepared = true; * lazyLoad(); * 3:重写lazyLoad(){ * if (!mIsprepared || !mIsVisible || mHasLoadedOnce) { * return; * } * mHasLoadedOnce = true; * //UI和业务逻辑 * } * 4:拓展方法 * stopLoad()://当视图已经对用户不可见并且加载过数据, * //如果需要在切换到其他页面时停止加载数据,可以覆写此方法 * //此方法只在Fragment之间切换生效 * visibleToUser(): 用户可看见当前的Fragment (神策埋点需要) * inVisibleToUser():用户看不见当前的Fragment,包含Fragment之间切换和跳转到Activity (神策埋点需要) */ public abstract class BaseLazyFragment extends Fragment { /** * 判断当前的Fragment是否可见(相对于其他的Fragment) */ protected boolean mIsVisible; /** * 标志位,标志已经初始化完成 */ protected boolean mIsprepared; /** * 是否已被加载过一次,第二次就不再去请求数据了 */ protected boolean mHasLoadedOnce; @Override public void setUserVisibleHint(boolean isVisibleToUser) { //设置Fragment的可见状态 super.setUserVisibleHint(isVisibleToUser); if (getUserVisibleHint()) {//getUserVisibleHint获取Fragment可见状态 mIsVisible = true; onVisible(); } else { mIsVisible = false; onInvisible(); } if (isResumed()) { onVisibilityChangedToUser(isVisibleToUser); } } /** * 可见 */ protected void onVisible() { lazyLoad(); } /** * 不可见 */ protected void onInvisible() { stopLoad(); } /** * 延迟加载 * 子类必须重写此方法 */ protected abstract void lazyLoad(); /** * 当视图已经对用户不可见并且加载过数据,如果需要在切换到其他页面时停止加载数据,可以覆写此方法 */ protected void stopLoad() { } //region 神策埋点需要,统计Fragement 可见时间 @Override public void onResume() { super.onResume(); if (getUserVisibleHint()) { onVisibilityChangedToUser(true); } } @Override public void onPause() { super.onPause(); if (getUserVisibleHint()) { onVisibilityChangedToUser(false); } } /** * 当Fragment对用户的可见性发生了改变的时候就会回调此方法 * * @param isVisibleToUser true:用户能看见当前Fragment;false:用户看不见当前Fragment */ public void onVisibilityChangedToUser(boolean isVisibleToUser) { if (isVisibleToUser) { visibleToUser(); } else { inVisibleToUser(); } } protected void visibleToUser() { } protected void inVisibleToUser() { } //endregion }

ViewPagerActivity

public class ViewPagerActivity extends AppCompatActivity {
    private String[] TITLES = {"语文", "数学", "英语", "化学", "物理", "生物"};

    SwipeRefreshLayout mSwipeRefreshLayout;
    TabLayout mTabLayout;
    ViewPager mViewPager;

    private ViewPagerAdapter mAdapter;
    private int mCurrentIndex;

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

        mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
        mTabLayout = (TabLayout) findViewById(R.id.tab_layout);
        mViewPager = (ViewPager) findViewById(R.id.view_pager);

        mAdapter = new ViewPagerAdapter(getSupportFragmentManager(), TITLES);
        mViewPager.setAdapter(mAdapter);
        mViewPager.setCurrentItem(0);
        mViewPager.setOffscreenPageLimit(TITLES.length - 1);
        mTabLayout.setupWithViewPager(mViewPager);

        final Handler handler = new Handler(Looper.getMainLooper());
        mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                loadData();

                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mSwipeRefreshLayout.setRefreshing(false);
                    }
                }, 1000);
            }
        });

        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                mCurrentIndex = position;
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }

    private void loadData() {
        String[] titles = {"语文1", "数学1", "英语1", "化学1", "物理1", "生物1"};
        mAdapter.setTitles(titles);
    }
}

activity_view_pager



    

        

        

        

    




<style name="MyTablayoutStyle" parent="Widget.Design.TabLayout">
    <item name="tabIndicatorColor">#ff4f47item>
    <item name="tabSelectedTextColor">#4d4d4ditem>
    <item name="tabBackground">@android:color/whiteitem>
    <item name="tabTextAppearance">@style/MyTabLayoutTextAppearanceitem>
style>


<style name="MyTabLayoutTextAppearance" parent="TextAppearance.AppCompat.Widget.ActionBar.Title">
    <item name="android:textColor">#999999item>
    <item name="android:textSize">14spitem>
style>

ViewPagerAdapter

public class ViewPagerAdapter extends FragmentStatePagerAdapter {
    private String[] mTitles;
    public ViewPagerAdapter(FragmentManager fm, String[] titles) {
        super(fm);
        mTitles = titles;
    }
    @Override
    public Fragment getItem(int position) {
        EmptyFragment fragment = EmptyFragment.newInstance(mTitles[position]);
        Log.e("zrg", "getItem: 当前位置position=" + position);
        return fragment;
    }

    @Override
    public int getCount() {
        return mTitles == null ? 0 : mTitles.length;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Log.e("zrg", "instantiateItem: 当前位置position=" + position);
        return super.instantiateItem(container, position);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mTitles == null ? "" : mTitles[position];
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    public void setTitles(String[] titles) {
        mTitles = titles;
        notifyDataSetChanged();
    }
}

EmptyFragment

public class EmptyFragment extends BaseLazyFragment {
    private static final String ARG_TITLE = "arg_title";

    TextView mTvClick;

    private String mTitle;

    public EmptyFragment() {
    }

    public static EmptyFragment newInstance(String title) {
        EmptyFragment fragment = new EmptyFragment();
        Bundle bundle = new Bundle();
        bundle.putString(ARG_TITLE, title);
        fragment.setArguments(bundle);
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mTitle = getArguments().getString(ARG_TITLE);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_empty, container, false);
        mTvClick = (TextView) view.findViewById(R.id.tv_click);
        mIsprepared = true;
        lazyLoad();
        return view;
    }

    @Override
    protected void lazyLoad() {
        if (!mIsprepared || !mIsVisible || mHasLoadedOnce) {
            return;
        }
        mHasLoadedOnce = true;
        //UI和业务逻辑
        Log.e("zrg", "lazyLoad: 当前的fragment是:" + mTitle);
        mTvClick.setText(mTitle);
    }

    public String getTitle() {
        return mTitle;
    }
}
fragment_empty


    

注意事项

    1、更新fragment不能使用重新设置adapter的方式,只能通过adapter.setTitle(args...)让adapter完成更新。

private void errorLoadData(){
        String[] titles = {"语文1", "数学1", "英语1", "化学1", "物理1", "生物1"};
        mAdapter = new ViewPagerAdapter(getSupportFragmentManager(), titles);
        mViewPager.setAdapter(mAdapter);
        mViewPager.setCurrentItem(mCurrentIndex);
        mViewPager.setOffscreenPageLimit(titles.length - 1);
        mTabLayout.setupWithViewPager(mViewPager);
    }
    

源码地址:https://github.com/zrg1215/ViewPagerRefreshDemo

源码包括ScrollableLayout三段式悬浮布局,实现方式大致相同,由于切换的时候需要知道当前fragment,源码里有 ,如果不了解ScrollableLayout的童鞋, 传送门。


你可能感兴趣的:(ViewPager+Fragment刷新更新Fragment)