转载自 hdszlk的博客     原文链接:https://www.2cto.com/kf/201607/530540.html

1.一直以来的疑问

Fragment在ViewPager到底经历了哪些生命周期方法?到底发生了什么?

常会TabLayout和ViewPager配合起来使用,针对这套组合,就想也做一些学习了解。在一个ViewPager中经常会存在多个Fragment,Fragemnt在ViewPager中的生命周期一直没有闹明白。这周正好在测试Api的时候又用到了TabLayout和ViewPager组合。ViewPager中的Fragment并想做到延迟加载,在可见的时候再进行网络请求。在敲代码的时候想到到几个问题:

在ViewPager中,滑动时,Fragment会经历哪些生命周期? ViewPager的setOffscreenPageLimit()方法对Fragment有哪些影响? 在ViewPager中,Fragment的setUserVisibleHint()对Fragment的生命周期有哪些影响? 点击TabLayout的Tab时,Fragment经历的生命周期和滑动ViewPager有啥不一样?

现在有个明确的需要:在TabLayout和ViewPager这个组合下,实现Fragment的延迟加载。

2.Tablayout、ViewPager组合

代码很简单,就是新建一个Android Stuido工程,一个Activity里面有一个TabLayout和ViewPager,ViewPager中四个Fragment。

2.1布局文件

Acivity的布局文件:

?

1

2

3

4

5

6

7

8

9

10

11

    

        

            

    </android.support.design.widget.tablayout></android.support.v7.widget.toolbar></android.support.design.widget.appbarlayout>

   

</android.support.v4.view.viewpager></android.support.design.widget.coordinatorlayout>

主要是CoordinatorLayout、AppBarLayout和Toolabr的使用。如果基础的用法不知道的话可以看看CoordinatorLayout、Tablayout、Toolbar简单组合使用,我写的很基础的用法。啊哈哈 :)


Fragment的布局:

?

1

2

3

4

5

<framelayout android:layout_height="match_parent" android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android">

    

        <textview android:gravity="center" android:layout_height="match_parent" android:layout_width="match_parent" android:text="1" android:textcolor="@color/colorPrimary" android:textsize="150sp">

    </textview></android.support.v4.widget.nestedscrollview>

</framelayout>

Fragmentde的布局更加简单,主要就一个TextView。4个Fragment布局一样,就贴出一个。

2.2Actiity代码

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

public class MainActivity extends AppCompatActivity {

    private TabLayout tabLayout;

    private ViewPager viewPager;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

        setSupportActionBar(toolbar);

        initView();

    }

    private void initView() {

        tabLayout = (TabLayout) findViewById(R.id.tab_main_activity);

        viewPager = (ViewPager) findViewById(R.id.vp_main_activity);

        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());

        viewPager.setAdapter(adapter);

        List <fragment> data = new ArrayList<>();

        data.add(new Fragment_1());

        data.add(new Fragment_2());

        data.add(new Fragment_3());

        data.add(new Fragment_4());

        adapter.setFragmentList(data);

        tabLayout.setupWithViewPager(viewPager);

        for (int i = 0 ; i < adapter.getCount() ; i ++){

             tabLayout.getTabAt(i).setText("Tab_"+(i+1));

        }

    }

}

</fragment>

主要就是initView()这个方法。主要就是把4个Fragment加入到ViewPager中。


2.3Fragment代码

Fragemnt的生命周期方法共有11个,为了下面能够更加清晰记住这些生命周期,我给这些生命周期方法从1到11定了编号。如下:

?

1

2

3

1 onAttach()           --> 2 onCreate()      --> 3 onCreateView()    --> 4 onCreateActivity()

--> 5 onStart()        --> 6 onResume()      --> 7 onPause()         --> 8 onStop()

--> 9 onDestroyView()  --> 10 onDestroy()     --> 11 onDetach()

Fragment原本打算偷懒,只想写一套,不想写4个。但写一个的话onAttach()不好做区分展示,就又老老实实写了四个。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

public class Fragment_1 extends Fragment {

    private final String TAG = "Fragment_1";

    @Override

    public void onAttach(Context context) {

        super.onAttach(context);

        log("   1__onAttach");

    }

    @Override

    public void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        log("    2__onCreate");

    }

    @Nullable

    @Override

    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        log("    3_onCreateView");

        return inflater.inflate(R.layout.fragment_layout_1,container,false);

    }

    @Override

    public void onActivityCreated(@Nullable Bundle savedInstanceState) {

        super.onActivityCreated(savedInstanceState);

        log("   4__onActivityCreated");

    }

    @Override

    public void onStart() {

        super.onStart();

        log("   5__onStart");

    }

    @Override

    public void onResume() {

        super.onResume();

        log("   6__onResume");

    }

    @Override

    public void onPause() {

        super.onPause();

        log("   7__onPause");

    }

    @Override

    public void onStop() {

        super.onStop();

        log("   8__onStop");

    }

    @Override

    public void onDestroyView() {

        super.onDestroyView();

        log("   9__onDestroyView");

    }

    @Override

    public void onDestroy() {

        super.onDestroy();

        log("   10__onDestroy");

    }

    @Override

    public void onDetach() {

        super.onDetach();

        log("   11__onDetach");

    }

    private void log (String methodName){

        Log.e(TAG,"-------->"+methodName);

    }

}


代码全部贴完。都很简单。前面一个说了4个问题,到了思考第2,3个问题时,代码需要小改动。

3.开始分析问题 1

在ViewPager中,滑动时,Fragment会经历哪些生命周期?

开始前,这里没有图,就简单交代一下,每个Fragment有一个对应的数字。TAB-1 对应Fragment-1,以此类推,4个TAB对应于4个Fragment。默认显示Fragment1。

3.1 滑动ViewPager,切换Fragment

这部分所有的切换Fragment都是通过滑动ViewPager。不是点击Tab。在Activity中,ViewPager此时啥都没有设置。


3.1.1 加载Fragment_1

当Activity中ViewPager加载完成时,手机屏幕显示默认的Fragment1。此时,打印的Log信息:

此时打印的Log信息与预想的有很大不同。知道ViewPager会有预加载的特性,我以为Fragment_1会从 1 onAttach() 开始直到 6 onResume()后,Fragment_2才会开始从 1onAttach()开始,到了3 onCreateView()会停止。然而,并不是预想的这样。

首先,Fragment_1 经历 1_onAttach() 和 2_onCreate() 后, Fragment_2也开始走了 1_onAttach()和 2_onCreate()方法。<喎�"/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPr3T18WjrEZyYWdtZW50XzHSwLTOvq3A+iAzX29uQ3JlYXRlVmlldygpLCA0X29uQ3JlYXRlQWN0aXZpdHkoKSw1IF9vblN0YXJ0ICw2X29uUmVzdW1lKCmho7TLyrGjrEZyYWdtZW50XzG78bXDvbm146Os0tG+rdW5yr7U2srWu/rGwcS7oaNGcmFnbWVudF8y0rK909fFtNMgM19vbkNyZWF0ZSgpv6rKvNaxtb3Ssta00NC1vSA2X29uUmVzdW1lKCm3vbeooaPSyc7Kvs3U2tXio6zO0rj2yMu40L71vMjIu0ZyYWdtZW50XzLDu9PQ1NrGwcS7z9TKvqOsvs2yu7vh1rTQ0LW9IDZfb25SZXN1bWUoKbe9t6gsyLu2+ExvZ9DFz6LItM/Uyr7WtNDQtb3ByyA2X29uUmVzdW1lKCmho9XiwO+8x8K80rvPwqGjPC9wPg0KPGhyIC8+DQo8aDMgaWQ9"312-由fragment1向右滑动到fragment2">3.1.2 由Fragment_1向右滑动到Fragment2_

滑动一下屏幕,ViewPager中由Fragment_1切换到Fragment_2,,屏幕显示Fragment_2时,下面是Log信息:

哎,我擦,咋就只有Fragment_3的信息,Fragment_1和Fragment_2的呢?这Fragment_2没有Log信息可以理解,可Fragment_1应该会有啊。这里又和预想的大不一样。预想中Fragment_1会走 7__onPause(),8__onStop(),9__DestroyView()和10__ononDestroy()。而实际却没有走,开始还以为搞错了,又反复测试,发现就是只有Fragment_3的Log信息。

根据Log信息,可以看出,当滑到Fragment_2后,Fragment_3经历了从 1__onCreate()方法到6__onResume()方法。Fragment_1却是没有走任何生命周期方法。这里考虑了一下,感觉也蛮合理。ViewPager展示的时候,用户在实际使用的时候,经常会从一个Fragment滑到另一个Fragment后又切换回来。这时如果按照我预想的,Fragment_1中的View已经被销毁,再次切换回来又需要重新绘制,这样频繁请求内存空间也不好。

这时,Fragment_3已经时刻准备好,如果在onCreateView()方法中有网络请求的话,网络请求在滑动到Fragment_2后就会被调用。就等着滑动ViewPager后,来展示内容。

这里先预留问题滑到Fragment_2后,Fragment_1没有走任何生命周期方法,Fragment_1的生命周期方法会在啥时候走?

当Fragment_2在屏幕时,这时候就有了两个方向可以选择,左滑到Fragment_1 或者 右滑到 Fragment_3。同理,当屏幕显示Fragment_3的时候,也是有两个方向可选择。

3.1.3 由Fragment_2向右滑到Fragment_3

前面已经提到,当由Fragment_1滑到Frament_2后,Fragment_3的生命周期方法已经从 1_onCreate()走到了 6_onResume()。当滑到Fragment_3后,看下此时的Log信息。

这次,Fragment_4先走了 1_onAttach(),2_onCreate()后,Fragment_1走 7_onPause,8_onStop,9_onDestroyView()。Fragment_1的生命周期终于开始走。而此时,Frment_4也已经完成了预加载。这里也可以解答3.1.2最后预留的那个问题。

看到了这次的Log信息,终于感觉看出了点ViewPager中嵌套Fragment后一些特点。

当ViewPager中的Fragment大于等于3个的时候,除去展示开头和结尾两个Fragment的情况,ViewPager会保留一个Fragment左右两侧以及自身3个Fragment的信息。例如,当滑到Fragment_2的时候,Fragment_3也已经走到了6_onResume()这个生命周期方法,而此时,Fragemnt_1没有走任何的生命周期方法,还在ViewPager中保留着。此外还有,当加载本身或者预加载下一个Frgment时,只是先走1_onAttach()和2_onCreate()两个生命周期方法后,才会根据当前情况确定继续走相应的Fragment的生命周期方法。


3.1.4 由Fragment_2向左滑到Fragment_1

当由Frament_1滑到Fragment_2时,并没有走Fragment_1和Fragment_2的生命周期,而是走了Fragment从1_onCreate()到6_onResume()。接下来,屏幕向左滑,由Fragment_2滑到Fragment_1。Log信息:

由Fragment_1滑到Fragment_2只是走了Fragment_3的生命周期方法,而由Fragment_2滑到Fragment_1时,也是只走了Fragment的生命周期方法。在3.1.2中,当滑到Fragment_2后,Fragment_3已经走到了6_onResume()方法。再滑到Fragment_1后,Fragment_3走了7_onPause(),8_onStop(),9_onDestoryView()。到了这里发现,在ViewPager中,相邻的3个Fragment之间来回切换,都没有走10_onDestroy()和11_onDetach()。


到了这里,四个Fragment滑动的情况再分析查看下面的3种情况。其实,下面的这些情况和前面的情况重复了,本质是一样的。

由Fragment_3向右滑到Fragment_4 由Fragment_3向左滑到Fragment_2 由Fragment_4向左滑到Fragment_3


3.1.5 由Fragment_3向右滑到Fragment_4

滑动前,当屏幕显示Fragment_3时,此时,由3.1.3知道,Fragment_1走到了9_onDestroyiew()。Fragment_4走到了6_onResume()。
滑到Fragment_4后:

Fragment_4是ViewPager中最后一个Fragment所以也就没了下一个Fragment预加载。只是不相邻的Fragment_2走了7_pause(),8_onStop,9_onDestroyView()方法。此时,就可以结合3.1.3情况来看。实际的情况是一样的,只是区别在于Fragment_4已经是最后一个Fragment了。


3.1.6 由Fragment_3向左滑到Fragment_2

这里结合3.1.4,很容易就理解了。
滑动前,当屏幕显示Fragment_3时,此时,由3.1.3知道,Fragment_1走到了9_onDestroyiew()。Fragment_4走到了6_onResume()。
滑动到Fragment_2后:

根据3.1.3中的Log信息,Frgment_1在由Fragment_2滑到Fragment_3的时候,生命周期已经走到了9_onDestroyView(),并没有走到10_onDestroy()。当由Fragment_3滑到Fragment_2后,ViewPager再次预加载Fragment_1时,是从3_onCreateView()开始的,走到4_onCreateAcitivty()后,开始走Fragment_4的生命周期方法7_onPause(),8_onStop(),9_onDestroyView(),之后,Fragment_1的生命周期走4_onCreateActivity(),5_onStart(),6_onResume()。


3.1.7 由Fragment_4向左滑到Fragment_3

滑动前,当显示Fragment_4时,根据3.1.5的Log信息,Fragment_2走到了9_onDestroyView()生命周期方法。而Fragment_3和Fragment_4此时都处于6_onResume()这个生命周期方法。
滑动到Fragment_3后:

到了这里,就比较容易理解此时的Log信息。Fragment_2从3_onCreateView()走到了6_onResume()方法。到了此时,Fragment_2、Fragment_3和Fragment_4此时3个Fragment都处于6_onResume()这个生命周期方法。


到了这里,ViewPager中Fragment滑动的情况就差不多分析完了。其他都是些重复的情况了。根据3.1.1到3.1.7的Log来看,ViewPager中嵌套Fragment默认不设置其他方法时,若Fragment的数量大于等于3时,ViewPager会保留包括一个Fragment在内左右两侧3个Fragment的信息。然而这里也留下了个问题,Fragment的10_onDestroy和11_onDetach()什么时候会走?

3.1.8 点击回退键finish掉Acitivty时

根据3.1.7的信息,此时,Fragment_1处于9_onDestroyView()这个生命周期方法,Fragment_2、Fragment_3和Fragment_4此时3个Fragment都处于6_onResume()这个生命周期方法。
此时,点击back键结束当前的Acitivty,我这里整个测试的App就一个Activity,点击了back键就会退出应用。看下此时的Log信息:

根据Log信息,Fragment_2,3,4先走了7_onPause()后,走了8_onStop()。接着,便是Fragment_1走10_onDestroy(),11_onDetach()。之后便是Fragment_2,3,4依次走9_onDestroyView(),10_onDestroy(),11_onDetach()。

到了这里,3.1.7的问题也就有了答案。ViewPager中,Fragment的10_onDestroy()以及11_onDetach()会在ViewPager所在的Activity结束后被调用。

这里还有一点需要说的是,点击back键后,图(点击Back键时)中的Log信息并不是一次打印出来的。一开始我以为是我是看错了,又测试了几次,发现,Fragment_2,3,4走了7_onPause()这个方法后,确实会短暂停一下,非常快的又打印出下面的Log信息。

3.1.8 当屏幕显示Fragment_3时,点击电源键关闭屏幕

当屏幕正在展示某个Fragment时,点击了电源键或者手机自动息屏时,这种情况下,会和以上的几种情况有所不同,下面还是以Fragment_3为例来尝试分析一下。

根据3.1.7的信息,此时,Fragment_1处于9_onDestroyView()这个生命周期方法,Fragment_2、Fragment_3和Fragment_4此时3个Fragment都处于6_onResume()这个生命周期方法。

点击电源键之后:


Fragment_2,3,4依次走了7_onPause(),8_onStop()。接下来,再点亮屏幕,显示Fragment_3:

Fragment_2,3,4依次走了5_onStart(),6_onResume()。


到了此时,ViewPager中Fragment滑动的情况就结束了。这些情况,写一个很简单的测试demo就可以搞的比较清楚了。要一次就记得清楚也不算特别现实,多想几次就可以了。

4.尝试分析问题2

ViewPager的setOffscreenPageLimit()方法对Fragment有哪些影响?

直白翻译就是设置幕后页面限制 :) 。其实就是设置预加载Fragment的数量。

?

1

2

3

4

5

6

7

8

9

10

11

public void setOffscreenPageLimit(int limit) {

       if (limit < DEFAULT_OFFSCREEN_PAGES) {

           Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +

                   DEFAULT_OFFSCREEN_PAGES);

           limit = DEFAULT_OFFSCREEN_PAGES;

       }

       if (limit != mOffscreenPageLimit) {

           mOffscreenPageLimit = limit;

           populate();

       }

   }

通过ViewPager中源码可以看出,传入的参数如果小于DEFAULT_OFFSCREEN_PAGES(就是1)这个值是无效的。所以尝试使用setOffscreenPageLimit(0)来关闭ViewPager的预加载是无效。也就是说,limit只有大于等于2时才会有效。Ps:ViewPager调用这个方法后,里面populate()这个方法又做了啥,我目前想关心也关心不了,大概看了下,ViewPager共有3000多行代码,我目前的代码阅读能力还很低,即使想做到只是阅读相关代码也困难,目前想读通比较困难,以后代码阅读能力提升再来看了。

接下来,改动代码,在ViewPager中,加入viewPager.setOffscreenPageLimit(2)这行代码,再次运行,看看Log信息。

根据问题1的分析,看到这个Log信息就很好理解了,多了Fragment_3的Log信息,而且走的方法和Frgment_1和2是一样的。后面的情况的Log信息便不再贴出来了,本质是一样的,只是多预加载了一个Fragment。但此时ViewPager依然只是保留3个Fragment的信息。当滑到Fragment_4的时候,Fragment_1走了7_onPause(),8_onStop(),9_onDestroyView()。Fragment_2,3,4则处于6_onResume()。

这个方法对Fragment生命周期方法的调用顺序上并没有什么影响,只是预加载的Fragment的数量又设置的limit参数决定。

6.尝试分析问题3

在ViewPager中,Fragment的setUserVisibleHint()对Fragment的生命周期有哪些影响?

再次顾名思义:设置用户可见暗示 。:) 这个方法可以用来判断Fragment是否可见。这里也不再贴源码了。

6.1 Fragment加入setUserVisibleHint()

修改代码前,我把在分析问题2时加入的viewPager.setOffscreenPageLimit(2)注释掉。这样Log信息会少一些。在每个Fragment中代码做了一些修改加入了一个setUserVisibleHint()。

?

1

2

3

4

5

6

<code><code><code>    @Override

    public void setUserVisibleHint(boolean isVisibleToUser) {

        super.setUserVisibleHint(isVisibleToUser);

        log("setUserVisibleHint");

    }</code></code></code>

再次运行Demo,查看Log信息:

和预想的大不一样。setUserVisibleHint()竟然最先被调用。预想的是1_onAttach()执行后,才会走setUserVisibleHint()这个方法。而且,Fragment_1走了两次setUserVisibleHint()这个方法。其他的Log信息倒是比较熟悉了。
滑动屏幕,滑动到Fragment_2,看下此时的Log信息:

这时不仅先执行了Fragment_3的setUserVisibleHint(),连Fragment_1,2的setUserVisibleHint()方法也比Fragment_3的1_onAttach()。此时,Fragment_1,2,3都处于6_onResume()。再由Fragment_2滑到Fragment_1,看下Log:

此时,Fragment_1,2的setUserVisibleHint()方法优先被调用,Fragment_3走到9_onDestroyView()方法。

到了这里,感觉setUserVisibleHint()这个方法每次滑动都会被调用,而且最先被调用,ViewPager中保存信息的Fragment都会被调用。

接下来模拟一下延迟加载网络请求。


6.2 延迟加载,模拟网络请求

在每个Fragment中,加入一个Boolean值,并将代码做一些改动。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

<code><code><code> @Override

    public void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        isCreate = true;

        log("   2__onCreate");

    }

    @Override

    public void setUserVisibleHint(boolean isVisibleToUser) {

        super.setUserVisibleHint(isVisibleToUser);

        if (isCreate && isVisibleToUser){

            log("开始进行网络请求了");

            isCreate = false;

        }

    }</code></code></code>

当Fragment可见时,进行网络请求。网络请求加上了前提条件。除了isVisibleToUser为true外还有一个isCreate。Fragment走了2_onCreate()iSCreate设为了true。我通常会用Fragment.newInstrance()这个方法进行初始化Fragment时来传值,在2_onCreate()方法中通过getArguments()来接收值,所以这里加了一个条件isCreate为true。


再次运行Demo,看Log信息:

我擦,我的”开始进行网络请求了”呢?最关键的Log信息却没有看到。根据6.1,每次肯定会调用setUserVisibleHint()这个方法的啊,可Fragment_1明明都已经可见了,怎么没有出现”开始进行网络请求了”?于是,看了下源码,…,白看,没瞧出啥。好吧,我再滑下屏幕,Fragment_2显示,看下Log:

滑到Fragment_2后,第一行倒是打印出来了”开始进行网络请求了”。继续滑,Fragment_3,4也都打印出来了。然后我又依次从Fragment_4滑到了Fragment_1后,Log信息也打出了”E/Fragment_1: ——–>开始进行网络请求了”。

可为啥Fragment_1第一次显示时,没有打印呢?
这里结合6.1想了一下,setUserVisibleHint()这个方法在1_onAttach()方法之前。Fragment_1第一次加载时,2_onCreate()方法还没走呢,此时isCreate的值还是fasle,就不会打印”开始进行网络请求了”。根据6.1的Log信息,Fragment_1两次调用setUserVisibleHint()时,isCreate都为false。而isCreate值变为true后,却不在执行setUserVisibleHint()方法了。

考虑到了原因了,把判断条件isCreate去掉也不是很合适。因为去掉了,此时也拿不到Fragment.newInstrance()传递过来的对象,往往网络请求的需要的参数需要这个传递过来的对象,会造成空指针。那怎么办?嗯,这是Fragment_1,第一个Fragment干嘛还要延迟加载啊。延迟加载的目的就是为了等到Fragment_2,3,4…这些后面的Fragment可见后再进行网络请求。Fragment_1没有太多必要加载。如果是考虑到用户从Fragment_4向左滑,滑到Fragment_2时,Fragment_1不会再次进行网络请求的话,可以考虑使用其他的方法。例如,设置下拉刷新,只有下拉刷新Fragment_1才再次进行网络请求。

于是,关于Fragment_1,我的处理是,不使用延迟加载。


7.尝试分析问题4

点击TabLayout的Tab时,Fragment经历的生命周期和滑动ViewPager有啥不一样?

问题1,2,3都是通过滑动来分析的,没有通过点击Tab。现在来看看点击Tab。

7.1 点击Tab时,Fragment所走的生命周期

开始前,把每个Fragment中的setUserVisibleHint()先注释掉,之后运行Demo。这里点击Tab_2是体现不出啥效果的,因为Fragment_2已经预加载了。我这里点击Tab_3,看Log信息:

到了这里,这个Log信息还是比较容易理解了。此时的Fragment_2,3,4处于6_onResume()这个方法。Fragment_1走到9_onDestroyView()。和滑动时其实没有本质的区别。就是点击可以从Fragment_1越过Fragment_2而直接到Fragment_3这种交互上的区别而造成的少了滑动时对Fragment_3的预加载。如果是从Fragment_1滑到Fragment_3,在滑到Fragment_2时,就已经完成了对Fragment_3的预加载。而通过点击的方式时,点击Tab_3后,Fragment_3是从1_onAttach()这个生命周期方法开始的。

7.2 点击Tab的方式和Fragment延迟加载遇到的问题

在6.2中遇到的一个问题就是,Fragment_1用了我写的那种延迟加载的方法时,第一次加载不会进行网络请求,只有再次滑到Fragment_1后才会进行网络请求。到了这里,同样也会引起这个问题。少了预加载,例如7.1中,直接点击Tab_3时,此时Fragment_3并没有预加载。setUesrVisibleHint()的方法又比1_onAttach()方法调用的早。会有和6.2中遇到的问题一样。第一次点击Tab_3后,并不会进行网络请求,只有再次滑动到Fragment_3后才会进行网络请求。


我的解决办法就是利用ViewPager.setoffscreenLimit(int limit);这个方法。根据情况,我将litmit设为了3。我这个方法比较粗暴,虽然有效但不好,而且局限性很大。一旦Tab可以编辑,并且数量不是固定的时候,这个方法就不好用了。而且预加载的数量多,肯定会需要更多的内存。这里,也希望有哪位大神有好的解决办法可以告诉我。

8 总结

这个周末用了一天半,写好了这篇博客,用来记录下我的学习过程。写的内容也是比较浅显,水平太菜,如果能有能力阅读源码,对于问题2,3,4会有更深入的了解,会有好的办法,而不是这篇博客中折中的方法。如果有啥错误,请赶紧指出。:)

9 补充

这篇博客刚刚发出去,就看到了另外一篇博客,专门讲的懒加载。看了下,发现我遗留的问题很容易就可以解决。
修改每个Fragment的代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

<code><code><code><code>@Override

    public void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        isCreate = true;

        log("   2__onCreate");

    }

    @Override

    public void setUserVisibleHint(boolean isVisibleToUser) {

        super.setUserVisibleHint(isVisibleToUser);

        load();

    }

    private void load() {

        if (isCreate && getUserVisibleHint() && !isHasLaodOnce){

            log("开始进行网络请求了");

            isCreate = false;

            isHasLaodOnce = true;

        }

    }

     @Override

    public void onActivityCreated(@Nullable Bundle savedInstanceState) {

        super.onActivityCreated(savedInstanceState);

        log("   4__onActivityCreated");

        load();

    }</code></code></code></code>

load()方法有3个前提条件,isCreate,可见,没有进行网络请求过。

根据6.1,setUserVisibleHint()这个方法会在预加载Fragment时,会在Fragment的1_onAttach()前调用。此时,在setUserVisibleHint()里面调用也不用害怕空指针的问题,因为有3个前条件。当通过滑动ViewPger时,根据6.1知道,每次滑动都会调用setUserVisibleHint()这个方法,进行预加载后,当滑到Fragment_2,3,4时,就会调用里面的load()方法。

针对6.2和7.2的问题。解决办法就是在Fragment的4_onCreateActivity()中调用load。我个人习惯把网络请求放在这个生命周期。在Fragment_1和点击Tab时,引起问题的原因就是setUserVisibleHint()先于1_onAttach()调用,不能满足前提条件中的isCreate,所以load方法不会被调用。而4_onCreateActivity()中会再次调用load()方法,此时还满足3个前提条件。这样,遗留的问题也解决了。ViewPager中Fragment延迟加载这个需求也可以实现了。如果此时Fragment中有一个轮播图的话,也可以通过getUserVisibleHint()这个方法来选择关闭轮播图线程的时机。

如果你看到了这里,真爱啊。十分感谢。

Fragment在ViewPager中的生命周期相关推荐

  1. android tab pageview,Android Fragment在ViewPager中到底经历了什么?

    2017年05月30 最后的懒加载写的不好,推荐请叫我大苏同学写的Fragment懒加载博客, [Android]再来一篇Fragment的懒加载(只加载一次哦) 在大苏同学的博客评论里,看到了另一个 ...

  2. TabLayout让Fragment在ViewPager中的滑动切换更优雅

    TabLayout让Fragment在ViewPager中的滑动切换更优雅 转载于:https://www.cnblogs.com/zhujiabin/p/7382500.html

  3. [JavaWeb-Servlet]Servlet中的生命周期方法(init,service,destroy)

    Servlet中的生命周期方法: @Override public void init(ServletConfig servletConfig) throws ServletException {}1 ...

  4. java session 生命周期_Java中httpsession生命周期

    Java中httpsession生命周期 HttpSession会话范围是某个用户从首次访问服务器开始,到该用户关闭浏览器结束,那么从用户访问到退出浏览器它的生命周期过程如下: 1. 当浏览器A向服务 ...

  5. 实现Fragment在ViewPager中滑动

    一.效果展示 二.前期准备 1.创建Fragment类 2.进入Fragment自动生成的布局文件设置布局 3.在Fragment类中初始化控件 public class Fragment1 exte ...

  6. Unity中场景生命周期的监听: EditorSceneManager

    本文分享Unity中场景生命周期的监听: EditorSceneManager 在Unity开发中, 有时我们需要在场景的某些生命周期时做一些特定的操作, 特别是在Editor模式下的一些工具代码. ...

  7. 小程序中的生命周期有哪些?

    一.小程序中生命周期的分类 小程序中的生命周期有以下三种: (1)应用生命周期 小程序的生命周期函数是在app.js中调用,通过App(Object)函数用来注册一个小程序,指定其小程序的生命周期回调 ...

  8. uni-app中的生命周期方法

    uni-app中的生命周期方法 -- 重点面试题 概念:LifeCycle Methods,方法名固定,无需自己调用,到了指定的时刻,会被框架自动调用.  1.应用级生命周期方法(App.vue) - ...

  9. flutter中的生命周期

    前言 和其他的视图框架比如android的Activity一样,flutter中的视图Widget也存在生命周期,生命周期的回调函数提现在了State上面.理解flutter的生命周期,对我们写出一个 ...

最新文章

  1. exec的不同实现--鸠占鹊巢还是功成身退
  2. Python算法实战系列:栈
  3. InfluxDB存储引擎Time Structured Merge Tree——本质上和LSM无异,只是结合了列存储压缩,其中引入fb的float压缩,字串字典压缩等...
  4. [转载] Python字符串常用操作命令
  5. 06向量及其坐标表示、向量的方向角与方向余弦、向量组共线与共面的条件、向量的加法与数乘运算、向量组的线性组合、二维向量的基向量分解、三维向量的基向量分解、用坐标做向量的数乘
  6. DB2 9 根本(730 检修)认证指南,第 6 局部: 数据并发性(2)
  7. 深度系统文件服务器,深度系统镜像文件
  8. iis php 映射,iis添加php的模块映射
  9. sqlserver 执行计划
  10. 兜兜转转 - 2019开启CSDN博客的新篇章
  11. 一个C/C++协程库的思考与实现之协程栈的动态按需增长
  12. maple 求特征值
  13. 图片与mat文件的转换
  14. SpringBoot通过自定义注解实现模板方法设计模式
  15. Activity onDestroy() 回调缓慢问题分析及完美解决方案
  16. 字字珠玑的百度员工离职总结
  17. 安卓低功耗蓝牙——手机作为外围设备
  18. 苹果安卓虚拟视频插件刷机包
  19. 成都计算机职高学校排名,成都计算机职高排名
  20. 买一台云服务器到底能做什么?

热门文章

  1. 安徽科技学院 信网学院网络文化节 曹健
  2. Linux基础命令大全(详细版)
  3. 打破“双十定律”,华为云AI推动超级抗菌药Drug X研发加速
  4. CAPL 脚本对.ini 配置文件的高阶操作
  5. 旅游行业数据可视化怎么做?快试试Smartbi一站式数据分析工具
  6. Java虚拟机如何设置环境变量_如果classpath环境变量没有进行设置,Java虚拟机会自动将其设置为“.”,也就是当前目录。...
  7. Echarts基础圆环图
  8. 直流供电电路中,关于电源并联二极管、电容作用的思考与总结
  9. GPRS联网过程简介
  10. 疯狂Java讲义:P200接口