欢迎访问宙启技术站
智能推送

Android之Viewpager+Fragment实现懒加载示例

发布时间:2023-05-14 07:20:54

Viewpager + Fragment 是我们 Android 开发中比较经常用到的一种组合。然而,在实际开发中,我们会发现 Fragment 的生命周期比较独特,而 Viewpager + Fragment 在配合使用时会出现一些让人头疼的问题,比如说 ViewPager 内的 Fragment 会在 ViewPager 初始化之后都会先执行一遍生命周期方法,导致了页面切换卡顿等问题。因此,我们需要通过一些技巧来解决这个问题,提升用户体验。

本文将介绍一种常见的解决方案,即实现 Fragment 的懒加载。这种方案可以让我们的 ViewPager 内的 Fragment 在切换时只加载当前展示的 Fragment,避免了无意义的性能开销。

下面就来具体讲解如何实现 Fragment 的懒加载。

# Fragment 的生命周期方法

为了实现 Fragment 的懒加载,我们需要了解 Fragment 的生命周期方法。一般而言,Fragment 的生命周期包括以下方法:

- onAttach:当 Fragment 被添加到 Activity 中时调用。

- onCreate:当 Fragment 被创建时调用。

- onCreateView:创建该 Fragment 的 View 时调用。

- onActivityCreated:当 Activity 的 onCreated 方法执行完后调用。

- onStart:当 Fragment 可见时调用。

- onResume:当 Fragment 可交互时调用。

- onPause:当 Fragment 失去焦点时调用。

- onStop:当 Fragment 不可见时调用。

- onDestroyView:当该 Fragment 的 View 被销毁时调用。

- onDestroy:当 Fragment 被销毁时调用。

- onDetach:当 Fragment 从 Activity 中移除时调用。

# 实现方式

那么,如何实现 Fragment 的懒加载呢?主要的思路就在 onCreateView 这个方法上。我们可以在该方法中判断 Fragment 是否已经准备好了数据,如果没有,再进行加载。

具体的实现可以参考下面这段代码:

    public class LazyFragment extends Fragment {
        private boolean isPrepared;
        private boolean isVisible;

        @Override
        public void setUserVisibleHint(boolean isVisibleToUser) {
            super.setUserVisibleHint(isVisibleToUser);
            if (getUserVisibleHint()) {
                isVisible = true;
                lazyLoad();
            } else {
                isVisible = false;
                onInvisible();
            }
        }

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            isPrepared = true;
        }

        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            return super.onCreateView(inflater, container, savedInstanceState);
        }

        /**
         * 懒加载
         */
        protected void lazyLoad() {
            if (!isPrepared || !isVisible) {
                return;
            }
            // 加载数据
        }

        protected void onInvisible() {
            // Fragment 不可见时的处理操作
        }
    }

在这里,我们使用了两个 Boolean 类型的变量,isPrepared 和 isVisible,分别代表该 Fragment 是否准备好了数据和是否可见。通过重写 setUserVisibleHint 方法和 onCreateView 方法,我们可以在 onCreateView 方法中判断是否需要加载数据。

其中,setUserVisibleHint 方法会在 Fragment 可见性发生变化时被调用,而 onCreateView 方法则会在创建 Fragment 的 View 时进行调用。在 setUserVisibleHint 方法中,根据变量 isVisible 判断 Fragment 是否可见,如果可见则调用 lazyLoad 方法进行加载;反之,则调用 onInvisible 方法进行处理。在 lazyLoad 方法中,根据变量 isPrepared 判断 Fragment 是否准备好了数据,如果都准备好了,则进行数据加载的操作。

# 在 AdapterView 和 FragmentPagerAdapter 中使用

当使用 AdapterView 和 FragmentPagerAdapter 等相关的类时,在使用 Fragment 进行懒加载时需要额外注意。

对于 AdapterView,我们需要重写 onWindowFocusChanged 方法,并在该方法中调用判断 Fragment 是否需要进行懒加载的操作。比如下面这样:

    public class LazyListView extends ListView {
        private boolean mIsFirstVisible;
        private boolean mIsVisible;

        public LazyListView(Context context) {
            super(context);
            init();
        }

        public LazyListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }

        public LazyListView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }

        private void init() {
            //       次可见
            mIsFirstVisible = true;
            // 是否可见
            mIsVisible = false;
        }

        @Override
        protected void onWindowVisibilityChanged(int visibility) {
            super.onWindowVisibilityChanged(visibility);
            if (visibility == VISIBLE) {
                if (mIsFirstVisible) {
                    mIsFirstVisible = false;
                    //       次可见时,需要进行加载
                    lazyLoad();
                } else {
                    // 如果已经不是      次出现,则需要判断 Fragment 是否可见
                    if (mIsVisible) {
                        lazyLoad();
                    }
                }
                mIsVisible = true;
            } else {
                mIsVisible = false;
            }
        }

        /**
         * 懒加载
         */
        private void lazyLoad() {
            // 加载数据
        }
    }

对于 FragmentPagerAdapter,我们可以在 getItem 方法中调用懒加载的操作,在 onCreateView 和 setUserVisibleHint 方法中判断是否需要进行加载操作。比如下面这样:

    public class LazyFragmentPagerAdapter extends FragmentPagerAdapter {
        private List<Fragment> mFragments;

        public LazyFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
            super(fm);
            mFragments = fragments;
        }

        @Override
        public Fragment getItem(int position) {
            Fragment fragment = mFragments.get(position);
            // 调用懒加载的操作
            Bundle bundle = new Bundle();
            bundle.putString("key", fragment.getClass().getSimpleName());
            fragment.setArguments(bundle);

            return fragment;
        }

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

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Fragment fragment = (Fragment) super.instantiateItem(container, position);
            Bundle bundle = fragment.getArguments();
            if (bundle != null) {
                String key = bundle.getString("key");
                if (TextUtils.equals(key, FragmentA.class.getSimpleName())
                        || TextUtils.equals(key, FragmentB.class.getSimpleName())) {
                    // 关键代码:重载 Fragment,改变实例 Fragment 的 setUserVisibleHint 时的回调逻辑
                    fragment.setUserVisibleHint(false);
                }
            }

            return fragment;
        }
    }

# 总结

以上就是实现 Fragment 的懒加载的一种常见方法。在实际开发中我们可以根据需求进行改造和优化。通过懒加载方案的实现我们可以有效减少无用资源的消耗,优化用户体验。