Viewpager + Fragment滑动时生命周期的回调顺序

最近在做一个项目中用到了viewpager+fragment实现的功能,但是出现了一些问题,尤其是fragment生命周期的问题,有人会说了这生命周期有什么难的,不就是按顺序回调么,显示回调哪些,隐藏回调哪些…… 这大家都知道的
其实这种问题经常出现在用到的fragment是相同的,比如说做题同一种题型我们就会用相同的fragment,因为里面的业务逻辑都是一样的,所以在这个时候我们切换题目的时候,就会因为生命周期而引起的业务逻辑上的问题。尤其在fragment里面用到单例模式时更要注意。
下面就通过代码示例讲一下viewpager切换fragment时生命周期的变化,以及每个fragment中调用的先后顺序(顺序这个很重要,顺序这个很重要,顺序这个很重要)。
首先新建一个Activity:

public class RecordActivity extends AppCompatActivity {

    ViewPager viewPager;
    List list;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_record_view);
        viewPager = findViewById(R.id.viewpager);
        list = new ArrayList<>();
        list.add(PlusOneFragment.newInstance());
        list.add(PlusTwoFragment.newInstance());
        list.add(PlusThreeFragment.newInstance());
        list.add(PlusFourFragment.newInstance());

        FragmentStatePagerAdapter adapter = new FragmentStatePagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int i) {
                return list.get(i);
            }

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

        viewPager.setAdapter(adapter);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.e("Activity","onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e("Activity","onResume");
    }
}

R.layout.activity_record_view如下:




    


RecordActivity里面很简单,就是初始化viewpager并设置adapter,这里用的是FragmentStatePagerAdapter

下面看一下4个fragment中的代码,因为4个fragment中的代码是一样的,就只贴出一个的代码

public class PlusOneFragment extends Fragment {

    public PlusOneFragment() {
        // Required empty public constructor
    }

    public static PlusOneFragment newInstance() {
        return new PlusOneFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e("Viewpager",this.getId()+"f1:onCreate");
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        Log.e("Viewpager",this.getId()+"f1:onCreateView");
        return inflater.inflate(R.layout.fragment_plus_one, container, false);
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.e("Viewpager",this.getId()+"f1:onResume");
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.e("Viewpager",this.getId()+"f1:onPause");
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Log.e("Viewpager",this.getId()+"f1:onAttach");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Log.e("Viewpager",this.getId()+"f1:onDetach");
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.e("Viewpager",this.getId()+"f1:onDestroyView");
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        Log.e("Viewpager",this.getId()+"f1:setUserVisibleHint");
    }
}

xml里面就一个按钮,代码就不贴出了,这里面把平常能用到的生命周期列出来并打印的log,this.getId()是判断当前的fragment是否创建,f1表示是第一个fragment,第二个fragment用f2标记,以此类推。

下面开始表演:
表演的顺序是打开,然后从做滑到右,再从右滑到左回到第一个fragment

第一种情况:打开RecordActivity时

07-02 14:55:18.872 mymvpapplication E/Activity: onStart
07-02 14:55:18.872 mymvpapplication E/Activity: onResume
07-02 14:55:18.884 mymvpapplication E/Viewpager: 0f1:setUserVisibleHint
07-02 14:55:18.884 mymvpapplication E/Viewpager: 0f2:setUserVisibleHint
07-02 14:55:18.884 mymvpapplication E/Viewpager: 2131165389f1:setUserVisibleHint
07-02 14:55:18.884 mymvpapplication E/Viewpager: 2131165389f1:onAttach
07-02 14:55:18.884 mymvpapplication E/Viewpager: 2131165389f1:onCreate
07-02 14:55:18.884 mymvpapplication E/Viewpager: 2131165389f2:onAttach
07-02 14:55:18.884 mymvpapplication E/Viewpager: 2131165389f2:onCreate
07-02 14:55:18.884 mymvpapplication E/Viewpager: 2131165389f1:onCreateView
07-02 14:55:18.884 mymvpapplication E/Viewpager: 2131165389f1:onViewCreated
07-02 14:55:18.884 mymvpapplication E/Viewpager: 2131165389f1:onStart
07-02 14:55:18.887 mymvpapplication E/Viewpager: 2131165389f1:onResume
07-02 14:55:18.887 mymvpapplication E/Viewpager: 2131165389f2:onCreateView
07-02 14:55:18.887 mymvpapplication E/Viewpager: 2131165389f2:onViewCreated
07-02 14:55:18.887 mymvpapplication E/Viewpager: 2131165389f2:onStart
07-02 14:55:18.889 mymvpapplication E/Viewpager: 2131165389f2:onResume

首先我们看第三、四行,this.getId()返回0,说明在fragment还没创建时就调用了setUserVisibleHint()方法,这个地方要注意一下,可以根据自己实际业务逻辑来进行懒加载。(用FragmentPagerAdapter时是可以返回Id的,此处还不是很明白为什么)
然后第一个fragment创建完之后还会再次回调一次setUserVisibleHint()方法,剩下的就是两个fragment正常走生命周期,顺序也要注意一下。

第二种情况:滑动至第二个fragment可见

07-02 14:55:38.824 mymvpapplication E/Viewpager: 0f3:setUserVisibleHint
07-02 14:55:38.824 mymvpapplication E/Viewpager: 2131165389f1:setUserVisibleHint
07-02 14:55:38.824 mymvpapplication E/Viewpager: 2131165389f2:setUserVisibleHint
07-02 14:55:38.824 mymvpapplication E/Viewpager: 2131165389f3:onAttach
07-02 14:55:38.824 mymvpapplication E/Viewpager: 2131165389f3:onCreate
07-02 14:55:38.825 mymvpapplication E/Viewpager: 2131165389f3:onCreateView
07-02 14:55:38.825 mymvpapplication E/Viewpager: 2131165389f3:onViewCreated
07-02 14:55:38.825 mymvpapplication E/Viewpager: 2131165389f3:onStart
07-02 14:55:38.827 mymvpapplication E/Viewpager: 2131165389f3:onResume

这种情况比较简单,首先回调第三个fragment中的setUserVisibleHint()方法(此时第三个fragment还没创建),然后是第一个fragment不可见,第二个fragment可见,第三个走完剩余的生命周期。

第三种情况:滑动至第三个fragment可见

07-02 17:17:08.327 mymvpapplication E/Viewpager: 0f4:setUserVisibleHint
07-02 17:17:08.327 mymvpapplication E/Viewpager: 2131165389f2:setUserVisibleHint
07-02 17:17:08.327 mymvpapplication E/Viewpager: 2131165389f3:setUserVisibleHint
07-02 17:17:08.327 mymvpapplication E/Viewpager: 2131165389f4:onAttach
07-02 17:17:08.328 mymvpapplication E/Viewpager: 2131165389f4:onCreate
07-02 17:17:08.328 mymvpapplication E/Viewpager: 2131165389f1:onPause
07-02 17:17:08.328 mymvpapplication E/Viewpager: 2131165389f1:onDestroyView
07-02 17:17:08.335 mymvpapplication E/Viewpager: 2131165389f1:onDestroy
07-02 17:17:08.335 mymvpapplication E/Viewpager: 2131165389f1:onDetach
07-02 17:17:08.335 mymvpapplication E/Viewpager: 2131165389f4:onCreateView
07-02 17:17:08.341 mymvpapplication E/Viewpager: 2131165389f4:onViewCreated
07-02 17:17:08.342 mymvpapplication E/Viewpager: 2131165389f4:onStart
07-02 17:17:08.342 mymvpapplication E/Viewpager: 2131165389f4:onResume

因为viewpager默认缓存左右两个fragment,所以这时候第四个fragment会预加载,但是第四个fragment的生命周期并不是一口气走完的,是先走到onCreate然后在由第一个fragment走不可见到销毁的生命周期,然后再次回到第四个fragment走完剩余的生命周期

第四种情况:滑动至第四个fragment可见

07-02 17:24:47.257 mymvpapplication E/Viewpager: 2131165389f3:setUserVisibleHint
07-02 17:24:47.257 mymvpapplication E/Viewpager: 2131165389f4:setUserVisibleHint
07-02 17:24:47.258 mymvpapplication E/Viewpager: 2131165389f2:onPause
07-02 17:24:47.258 mymvpapplication E/Viewpager: 2131165389f2:onDestroyView
07-02 17:24:47.260 mymvpapplication E/Viewpager: 2131165389f2:onDestroy
07-02 17:24:47.260 mymvpapplication E/Viewpager: 2131165389f2:onDetach

这种情况的生命周期还是比较简单的,第三个fragment不可见,第四个fragment可见(不调用其他生命周期,是因为之前已经预加载过了),然后第二个fragment销毁

第五种情况:由第四个fragment滑动至第三个fragment可见

07-02 17:30:23.973 mymvpapplication E/Viewpager: 0f2:setUserVisibleHint
07-02 17:30:23.973 mymvpapplication E/Viewpager: 2131165389f4:setUserVisibleHint
07-02 17:30:23.973 mymvpapplication E/Viewpager: 2131165389f3:setUserVisibleHint
07-02 17:30:23.973 mymvpapplication E/Viewpager: 2131165389f2:onAttach
07-02 17:30:23.973 mymvpapplication E/Viewpager: 2131165389f2:onCreate
07-02 17:30:23.974 mymvpapplication E/Viewpager: 2131165389f2:onCreateView
07-02 17:30:23.977 mymvpapplication E/Viewpager: 2131165389f2:onViewCreated
07-02 17:30:23.977 mymvpapplication E/Viewpager: 2131165389f2:onStart
07-02 17:30:23.977 mymvpapplication E/Viewpager: 2131165389f2:onResume

第六种情况:由第三个fragment滑动至第二个fragment可见

07-02 17:32:49.524 mymvpapplication E/Viewpager: 0f1:setUserVisibleHint
07-02 17:32:49.524 mymvpapplication E/Viewpager: 2131165389f3:setUserVisibleHint
07-02 17:32:49.524 mymvpapplication E/Viewpager: 2131165389f2:setUserVisibleHint
07-02 17:32:49.525 mymvpapplication E/Viewpager: 2131165389f1:onAttach
07-02 17:32:49.525 mymvpapplication E/Viewpager: 2131165389f1:onCreate
07-02 17:32:49.526 mymvpapplication E/Viewpager: 2131165389f4:onPause
07-02 17:32:49.526 mymvpapplication E/Viewpager: 2131165389f4:onDestroyView
07-02 17:32:49.528 mymvpapplication E/Viewpager: 2131165389f4:onDestroy
07-02 17:32:49.528 mymvpapplication E/Viewpager: 2131165389f4:onDetach
07-02 17:32:49.528 mymvpapplication E/Viewpager: 2131165389f1:onCreateView
07-02 17:32:49.530 mymvpapplication E/Viewpager: 2131165389f1:onViewCreated
07-02 17:32:49.530 mymvpapplication E/Viewpager: 2131165389f1:onStart
07-02 17:32:49.531 mymvpapplication E/Viewpager: 2131165389f1:onResume

这种情况和第三种情况差不多,其实就是反过来的

第七种情况:由第二个fragment滑动至第一个fragment可见

07-02 17:36:01.924 mymvpapplication E/Viewpager: 2131165389f2:setUserVisibleHint
07-02 17:36:01.924 mymvpapplication E/Viewpager: 2131165389f1:setUserVisibleHint
07-02 17:36:01.924 mymvpapplication E/Viewpager: 2131165389f3:onPause
07-02 17:36:01.924 mymvpapplication E/Viewpager: 2131165389f3:onDestroyView
07-02 17:36:01.925 mymvpapplication E/Viewpager: 2131165389f3:onDestroy
07-02 17:36:01.926 mymvpapplication E/Viewpager: 2131165389f3:onDetach

这种情况和第四种情况差不多,到此我们已经从左到右,又从右到左滑动一遍了,规律我们已经掌握的差不多了。

有讲的不对的地方,还请留言指出!

你可能感兴趣的:(Viewpager + Fragment滑动时生命周期的回调顺序)