ViewPager中的FragmentPagerAdapter,FragmentStatePagerAdapter

Posted android_xiaogang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ViewPager中的FragmentPagerAdapter,FragmentStatePagerAdapter相关的知识,希望对你有一定的参考价值。

在开发中ViewPager+fragment,包括缓存pager或者fragment中一些问题,什么时候该缓存销毁page,什么时候缓存销毁fragment问题
FragmentPagerAdapter,FragmentStatePagerAdapter的区别和适用场景

FragmentPagerAdapter

1、通过offscreenPageLimit来控制page container的cache数量 n*2+1;

2、当加载的page超出cache count会用FragmentManager来释放fragment

3、被释放的fragment实际上不会被完全回收,因为没有调用onDestory(),当再次回到这个page时也没有调用onCreate();

4、当fragment被显示在屏幕上时,setUserVisibleHint为true,不显示时为false.

适用于:
page是固定的,并且数量比较少,因为fragment不会被完全回收

FragmentStatePagerAdapter

其他三点都一样,不同的是
被释放的fragment会被完全回收,调用了onDestory()的方法;

适用于:
比较多的fragment,保证回收,清理内存

1、首先明确Fragment的生命周期

如果用ViewPager+fragment,首先应该明确fragment的生命周期,这个fragment什么时候开始创建,什么时候创建完成,什么时候创建view,什么时候可以加载数据。

几个重要容易模糊的生命周期
1、onAttach() 当一个fragment第一次绑定到它所属的activity中

 /**
     * Called when a fragment is first attached to its activity.
     * @link #onCreate(Bundle) will be called after this.
     * <p>Deprecated. See @link #onAttach(Context).
     */
    @Deprecated
    public void onAttach(Activity activity) 
        mCalled = true;
    

2、onCreate()它所属的activity正在创建中,并没有创建完成

 /**
     * Called to do initial creation of a fragment.  This is called after
     * @link #onAttach(Activity) and before
     * @link #onCreateView(LayoutInflater, ViewGroup, Bundle).
     * 
     * <p>Note that this can be called while the fragment's activity is
     * still in the process of being created.  As such, you can not rely
     * on things like the activity's content view hierarchy being initialized
     * at this point.  If you want to do work once the activity itself is
     * created, see @link #onActivityCreated(Bundle).
     * 
     * @param savedInstanceState If the fragment is being re-created from
     * a previous saved state, this is the state.
     */
    public void onCreate(@Nullable Bundle savedInstanceState) 
        mCalled = true;
    

3、onCreateView():可以把fragment的布局填充到view中,返回fragment的UI布局。

 /**
     * Called to have the fragment instantiate its user interface view.
     * This is optional, and non-graphical fragments can return null (which
     * is the default implementation).  This will be called between
     * @link #onCreate(Bundle) and @link #onActivityCreated(Bundle).
     * 
     * <p>If you return a View from here, you will later be called in
     * @link #onDestroyView when the view is being released.
     * 
     * @param inflater The LayoutInflater object that can be used to inflate
     * any views in the fragment,
     * @param container If non-null, this is the parent view that the fragment's
     * UI should be attached to.  The fragment should not add the view itself,
     * but this can be used to generate the LayoutParams of the view.
     * @param savedInstanceState If non-null, this fragment is being re-constructed
     * from a previous saved state as given here.
     * 
     * @return Return the View for the fragment's UI, or null.
     */
    @Nullable
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) 
        return null;
    

4、onActivityCreated():这时候activity创建完成,并且fragment布局已经填充进去。

  /**
     * Called when the fragment's activity has been created and this
     * fragment's view hierarchy instantiated.  It can be used to do final
     * initialization once these pieces are in place, such as retrieving
     * views or restoring state.  It is also useful for fragments that use
     * @link #setRetainInstance(boolean) to retain their instance,
     * as this callback tells the fragment when it is fully associated with
     * the new activity instance.  This is called after @link #onCreateView
     * and before @link #onViewStateRestored(Bundle).
     *
     * @param savedInstanceState If the fragment is being re-created from
     * a previous saved state, this is the state.
     */
    public void onActivityCreated(@Nullable Bundle savedInstanceState) 
        mCalled = true;
    

5、onDestroyView:销毁当前的view也就是填充的布局

 /**
     * Called when the view previously created by @link #onCreateView has
     * been detached from the fragment.  The next time the fragment needs
     * to be displayed, a new view will be created.  This is called
     * after @link #onStop() and before @link #onDestroy().  It is called
     * <em>regardless</em> of whether @link #onCreateView returned a
     * non-null view.  Internally it is called after the view's state has
     * been saved but before it has been removed from its parent.
     */
    public void onDestroyView() 
        mCalled = true;
    

6、onDestroy():销毁当前的fragment

  /**
     * Called when the fragment is no longer in use.  This is called
     * after @link #onStop() and before @link #onDetach().
     */
    public void onDestroy() 
        mCalled = true;
        //Log.v("foo", "onDestroy: mCheckedForLoaderManager=" + mCheckedForLoaderManager
        //        + " mLoaderManager=" + mLoaderManager);
        if (!mCheckedForLoaderManager) 
            mCheckedForLoaderManager = true;
            mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
        
        if (mLoaderManager != null) 
            mLoaderManager.doDestroy();
        
    

2、ViewPager中的适配器使用FragmentPagerAdapter

package com.example.yu.viewpager;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;

import com.example.yu.baseactivity.R;
import com.example.yu.viewpager.fragment.Fragment1;
import com.example.yu.viewpager.fragment.Fragment2;
import com.example.yu.viewpager.fragment.Fragment3;
import com.example.yu.viewpager.fragment.Fragment4;
import com.example.yu.viewpager.fragment.Fragment5;

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

public class MainActivity extends FragmentActivity 

    private ViewPager viewPager;

    private MyFragemtAdapter adapter;

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewPager = (ViewPager) findViewById(R.id.viewPager);
        List<Fragment> fragments = new ArrayList<Fragment>();

        fragments.add(new Fragment1());
        fragments.add(new Fragment2());
        fragments.add(new Fragment3());
        fragments.add(new Fragment4());
        fragments.add(new Fragment5());
        adapter = new MyFragemtAdapter(getSupportFragmentManager(), fragments);
        //设置缓存page的个数 2*n+1;
        viewPager.setOffscreenPageLimit(1);

        viewPager.setAdapter(adapter);
    

    class MyFragemtAdapter extends FragmentPagerAdapter 
        private List<Fragment> mFragments;

        public MyFragemtAdapter(FragmentManager fm, List<Fragment> fragments) 
            super(fm);
            mFragments = fragments;
        

        @Override
        public Fragment getItem(int position) 
            return mFragments.get(position);
        

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

Fragment1示例代码如下(其他四个也都一样)

package com.example.yu.viewpager.fragment;

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

import com.example.yu.baseactivity.R;

/**
 * Created by yu on 2016/6/12.
 */
public class Fragment1 extends Fragment 
    public static final String TAG = "Fragment1";

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
        View view = inflater.inflate(R.layout.fragment1, container, false);
        return view;
    

    @Override
    public void onDestroyView() 
        super.onDestroyView();
        Log.i(TAG, "fragment is onDestroyView()");
    

    @Override
    public void onDestroy() 
        super.onDestroy();
        Log.i(TAG, "fragment is onDestroy()");
    

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        Log.i(TAG, "fragment is onCreate()");
    

    @Override
    public void onActivityCreated(Bundle savedInstanceState) 
        super.onActivityCreated(savedInstanceState);
        Log.i(TAG, "fragment is onActivityCreated()");
    

3、ViewPager中的适配器使用FragmentStatePagerAdapter

其他代码都不动,只修改适配器类型为FragmentStatePagerAdapter

 class MyFragemtAdapter extends FragmentStatePagerAdapter 
        private List<Fragment> mFragments;

        public MyFragemtAdapter(FragmentManager fm, List<Fragment> fragments) 
            super(fm);
            mFragments = fragments;
        

        @Override
        public Fragment getItem(int position) 
            return mFragments.get(position);
        

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

从Log日志分析

以上是关于ViewPager中的FragmentPagerAdapter,FragmentStatePagerAdapter的主要内容,如果未能解决你的问题,请参考以下文章

LinearLayout 中的 ViewPager ListView。滑动 ViewPager 应该滑动整个页面吗?

如何在viewPager的视图顶部使用nestedScrollView中的viewpager

viewpager 中的剪辑布局

可滚动布局中的 ViewPager

SwipeRefreshLayout 干扰 ViewPager 中的 ScrollView

ViewPager 中的片段被重新创建