Fragment生命周期方法探究及懒加载模式实现

Fragment这个东西相信大家并不会陌生,最近在考虑Fragment的懒加载模式,顺便研究了Fragment的生命周期。

首先,先扔出这两张图
1、图示:
图一

这里写图片描述
图二

这里写图片描述
2 生命周期方法探究

通过上图我们可以清楚的看到Fragment的生命周期方法有:onAttach()、onCreate()、onCreateView()、onActivityCreated()、onStart()、onResume()、
onPause()、onStop()、onDestoryView()、onDestory()、onDetach()。

下面我们通过一个简单的例子来验证Fragment生命周期方法的执行顺序。这里我写了一个demo下面来看一下代码

(1)MainActivity.java


package com.fragment.admin.fragmenttext;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;

import com.fragment.admin.fragmenttext.fragment.Fragment01;
import com.fragment.admin.fragmenttext.fragment.Fragment02;
import com.fragment.admin.fragmenttext.fragment.Fragment03;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private ViewPager viewpager;
    private List<Fragment> list=new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        initViews();
    }

    private void initViews() {
        viewpager= (ViewPager) findViewById(R.id.viewpager);
        list.add(new Fragment01());
        list.add(new Fragment02());
        list.add(new Fragment03());

        viewpager.setAdapter(new viewPagerAdapter(getSupportFragmentManager()));

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    private class viewPagerAdapter extends FragmentPagerAdapter
    {

        public viewPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return list.get(position);
        }

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

代码很简单不多说了,我们以Fragment01 做为研究对象。

(2)Fragment01.java

package com.fragment.admin.fragmenttext.fragment;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.fragment.admin.fragmenttext.R;

/**
* Created by admin on 2016/11/1.
*/
public class Fragment01 extends BaseFragment {
    private static final String TAG = "Fragment01";

    private TextView tv_FragmentName;

//    /**
//     * 用于判断当前的Fragment是否可见
//     * @param isVisibleToUser
//     */
//    @Override
//    public void setUserVisibleHint(boolean isVisibleToUser) {
//        super.setUserVisibleHint(isVisibleToUser);
//        if (isVisibleToUser)
//        {
//            Log.e(TAG,"Fragment01可见");
//
//            return;
//        }
//        Log.e(TAG,"Fragment01不可见");
//
//    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Log.e(TAG, "onAttach");

    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.e(TAG, "onCreateView");
        View view = inflater.inflate(R.layout.item, container, false);
        initViews(view);
        return view;
    }

    @Override
    public void onLoad() {
        Log.e(TAG, TAG);
    }

    private void initViews(View view) {
        tv_FragmentName = (TextView) view.findViewById(R.id.tv_FragmentName);
        tv_FragmentName.setText(TAG);
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.e(TAG, "onPause");
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.e(TAG, "onStop");
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.e(TAG, "onDestroyView");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Log.e(TAG, "onDetach");
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(TAG, "onCreate");
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.e(TAG, "onStart");
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.e(TAG, "onResume");
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.e(TAG, "onActivityCreated");
    }
}

Fragment01的代码也相当简单,只是重写了其生命周期方法。

(3)测试
第一步:启动app(相当与是启动了Fragment01)

11-08 11:57:44.650 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onAttach
11-08 11:57:44.650 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onCreate
11-08 11:57:44.652 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onCreateView
11-08 11:57:44.661 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onActivityCreated
11-08 11:57:51.292 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onStart
11-08 11:57:51.293 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onResume

第二步:滑动到Fragment02
logcat没有任何变化

第三步:滑动到Fragment03

11-08 11:57:44.650 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onAttach
11-08 11:57:44.650 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onCreate
11-08 11:57:44.652 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onCreateView
11-08 11:57:44.661 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onActivityCreated
11-08 11:57:51.292 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onStart
11-08 11:57:51.293 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onResume
11-08 11:59:32.999 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onPause
11-08 11:59:32.999 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onStop
11-08 11:59:32.999 26181-26181/com.fragment.admin.fragmenttext E/Fragment01: onDestroyView

第四步:退出到桌面

11-08 13:37:13.507 24861-24861/com.fragment.admin.fragmenttext E/Fragment01: onAttach
11-08 13:37:13.507 24861-24861/com.fragment.admin.fragmenttext E/Fragment01: onCreate
11-08 13:37:13.510 24861-24861/com.fragment.admin.fragmenttext E/Fragment01: onCreateView
11-08 13:37:13.516 24861-24861/com.fragment.admin.fragmenttext E/Fragment01: onActivityCreated
11-08 13:37:13.516 24861-24861/com.fragment.admin.fragmenttext E/Fragment01: onStart
11-08 13:37:13.516 24861-24861/com.fragment.admin.fragmenttext E/Fragment01: onResume
11-08 13:37:20.868 24861-24861/com.fragment.admin.fragmenttext E/Fragment01: onPause
11-08 13:37:20.868 24861-24861/com.fragment.admin.fragmenttext E/Fragment01: onStop
11-08 13:37:20.868 24861-24861/com.fragment.admin.fragmenttext E/Fragment01: onDestroyView
11-08 13:37:30.751 24861-24861/com.fragment.admin.fragmenttext E/Fragment01: onDestroy
11-08 13:37:30.751 24861-24861/com.fragment.admin.fragmenttext E/Fragment01: onDetach

总结:以上四步可以完整的体现Fragment的生命周期,值得注意的是当调用onDestroyView方法时只是将Fragment中的View销毁掉了,当宿主Activity被销毁时Fragment才会被销毁。
3 Fragment懒加载模式实现以及原理

在项目中我们经常会使用ViewPager+Fragment的组合,默认的情况ViewPager会提前加载当前页的下一页以备不时之需。但是这样往往是比较消耗用户流量的,所以我们要选择懒加载模式
也就是所谓的需要的再来加载的模式。

(1)方法一:个人认为这个方法说了和没说是一样的,但是为了让我们知道一些关于ViewPager预加载模式的小九九我们还是说一下吧,不过看完以后小伙伴们别打我。
ViewPager里有一个setOffscreenPageLimit(int pageCount)方法,这个方法的作用就是设置预加载页的页数,参数pageCount默认是1。那么有人就想到了
我把参数设置为0不久ok了?没错,我之前也是这么想的,但是你测试就会发现并没有起作用。原因是~~~~
来来来让我们看一下源码

private static final int DEFAULT_OFFSCREEN_PAGES = 1;
/**
* Set the number of pages that should be retained to either side of the
* current page in the view hierarchy in an idle state. Pages beyond this
* limit will be recreated from the adapter when needed.
*
* <p>This is offered as an optimization. If you know in advance the number
* of pages you will need to support or have lazy-loading mechanisms in place
* on your pages, tweaking this setting can have benefits in perceived smoothness
* of paging animations and interaction. If you have a small number of pages (3-4)
* that you can keep active all at once, less time will be spent in layout for
* newly created view subtrees as the user pages back and forth.</p>
*
* <p>You should keep this limit low, especially if your pages have complex layouts.
* This setting defaults to 1.</p>
*
* @param limit How many pages will be kept offscreen in an idle state.
*/
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();
    }
}

limit是我们传入的页数DEFAULT_OFFSCREEN_PAGES是默认的页数,然而你会发现无论limit是几只要小与1,最终只能等于1。所以这个方法将失效!又有人说我们可以通过改变jar包将DEFAULT_OFFSCREEN_PAGES 的值改为0,这个方法我信。。。。。但是我们还是要说说方法二!

方法二:说到这个方法我们必须了解一个方法setUserVisbleHint(boolean),老规矩源码伺候

/**
* Set a hint to the system about whether this fragment's UI is currently visible
* to the user. This hint defaults to true and is persistent across fragment instance
* state save and restore.
*
* <p>An app may set this to false to indicate that the fragment's UI is
* scrolled out of visibility or is otherwise not directly visible to the user.
* This may be used by the system to prioritize operations such as fragment lifecycle updates
* or loader ordering behavior.</p>
*
* @param isVisibleToUser true if this fragment's UI is currently visible to the user (default),
*                        false if it is not.
*/
public void setUserVisibleHint(boolean isVisibleToUser) {
    if (!mUserVisibleHint && isVisibleToUser && mState < STARTED) {
        mFragmentManager.performPendingDeferredStart(this);
    }
    mUserVisibleHint = isVisibleToUser;
    mDeferStart = !isVisibleToUser;
}

关于这个方法的作用注视写的很清楚,大概意思是这样的

此处省去100字。。。

简而言之这个方法是告诉系统,Fragment的ui是否是用户可见的。如果是可见的那么isVisibleToUser是true否则是false。
为了方便我写了一个BaseFragment,让三个Fragment都继承它。

BaseFragment.java

package com.fragment.admin.fragmenttext.fragment;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
* Created by admin on 2016/11/1.
*/
public abstract class BaseFragment extends Fragment {
    private static final String TAG = "BaseFragment";

    private boolean isVisable=false;

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        Log.e(TAG, "setUserVisibleHint");
        if (isVisibleToUser) {
            Log.e(TAG, "BaseFragment 可见");
            isVisable=true;
            visable();
            return;
        }
        Log.e(TAG, "BaseFragment 不可见");
        isVisable=false;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    protected void visable()
    {
        onLoad();
    }

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

这个类中写了一个抽象方法onLoad()用于是子类的网络加载。由以上代码可以看出当Fragment处于可见状态时才回去调用onLoad()方法,从而实现了懒加载模式。

最后奉上源码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值