最近在做一个项目中用到了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
这种情况和第四种情况差不多,到此我们已经从左到右,又从右到左滑动一遍了,规律我们已经掌握的差不多了。
有讲的不对的地方,还请留言指出!