public abstract class

FragmentPagerAdapter

extends PagerAdapter

 java.lang.Object

androidx.viewpager.widget.PagerAdapter

↳androidx.fragment.app.FragmentPagerAdapter

Gradle dependencies

compile group: 'androidx.fragment', name: 'fragment', version: '1.5.0-rc01'

  • groupId: androidx.fragment
  • artifactId: fragment
  • version: 1.5.0-rc01

Artifact androidx.fragment:fragment:1.5.0-rc01 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.fragment:fragment com.android.support:support-fragment

Androidx class mapping:

androidx.fragment.app.FragmentPagerAdapter android.support.v4.app.FragmentPagerAdapter

Overview

Implementation of PagerAdapter that represents each page as a Fragment that is persistently kept in the fragment manager as long as the user can return to the page.

This version of the pager is best for use when there are a handful of typically more static fragments to be paged through, such as a set of tabs. The fragment of each page the user visits will be kept in memory, though its view hierarchy may be destroyed when not visible. This can result in using a significant amount of memory since fragment instances can hold on to an arbitrary amount of state. For larger sets of pages, consider FragmentStatePagerAdapter.

When using FragmentPagerAdapter the host ViewPager must have a valid ID set.

Subclasses only need to implement FragmentPagerAdapter.getItem(int) and PagerAdapter.getCount() to have a working adapter.

Here is an example implementation of a pager containing fragments of lists: frameworks/support/samples/Support4Demos/src/main/java/com/example/android/supportv4/app/FragmentPagerSupport.java complete

The R.layout.fragment_pager resource of the top-level fragment is: frameworks/support/samples/Support4Demos/src/main/res/layout/fragment_pager.xml complete

The R.layout.fragment_pager_list resource containing each individual fragment's layout is: frameworks/support/samples/Support4Demos/src/main/res/layout/fragment_pager_list.xml complete

Summary

Fields
public static final intBEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT

Indicates that only the current fragment will be in the state.

public static final intBEHAVIOR_SET_USER_VISIBLE_HINT

Indicates that Fragment.setUserVisibleHint(boolean) will be called when the current fragment changes.

from PagerAdapterPOSITION_NONE, POSITION_UNCHANGED
Constructors
publicFragmentPagerAdapter(FragmentManager fm)

Constructor for FragmentPagerAdapter that sets the fragment manager for the adapter.

publicFragmentPagerAdapter(FragmentManager fm, int behavior)

Constructor for FragmentPagerAdapter.

Methods
public voiddestroyItem(View container, int position, java.lang.Object object)

Remove a page for the given position.

public voidfinishUpdate(View container)

Called when the a change in the shown pages has been completed.

public abstract FragmentgetItem(int position)

Return the Fragment associated with a specified position.

public longgetItemId(int position)

Return a unique identifier for the item at the given position.

public java.lang.ObjectinstantiateItem(View container, int position)

Create the page for the given position.

public abstract booleanisViewFromObject(View view, java.lang.Object object)

Determines whether a page View is associated with a specific key object as returned by PagerAdapter.instantiateItem(ViewGroup, int).

public voidrestoreState(Parcelable state, java.lang.ClassLoader loader)

Restore any instance state associated with this adapter and its pages that was previously saved by PagerAdapter.saveState().

public ParcelablesaveState()

Save any instance state associated with this adapter and its pages that should be restored if the current UI state needs to be reconstructed.

public voidsetPrimaryItem(View container, int position, java.lang.Object object)

Called to inform the adapter of which item is currently considered to be the "primary", that is the one show to the user as the current page.

public voidstartUpdate(View container)

Called when a change in the shown pages is going to start being made.

from PagerAdapterdestroyItem, finishUpdate, getCount, getItemPosition, getPageTitle, getPageWidth, instantiateItem, notifyDataSetChanged, registerDataSetObserver, setPrimaryItem, startUpdate, unregisterDataSetObserver
from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

public static final int BEHAVIOR_SET_USER_VISIBLE_HINT

Deprecated: This behavior relies on the deprecated Fragment.setUserVisibleHint(boolean) API. Use FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT to switch to its replacement, FragmentTransaction.setMaxLifecycle(Fragment, Lifecycle.State).

Indicates that Fragment.setUserVisibleHint(boolean) will be called when the current fragment changes.

See also: FragmentPagerAdapter.FragmentPagerAdapter(FragmentManager, int)

public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT

Indicates that only the current fragment will be in the state. All other Fragments are capped at .

See also: FragmentPagerAdapter.FragmentPagerAdapter(FragmentManager, int)

Constructors

public FragmentPagerAdapter(FragmentManager fm)

Deprecated: use FragmentPagerAdapter.FragmentPagerAdapter(FragmentManager, int) with FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT

Constructor for FragmentPagerAdapter that sets the fragment manager for the adapter. This is the equivalent of calling FragmentPagerAdapter.FragmentPagerAdapter(FragmentManager, int) and passing in FragmentPagerAdapter.BEHAVIOR_SET_USER_VISIBLE_HINT.

Fragments will have Fragment.setUserVisibleHint(boolean) called whenever the current Fragment changes.

Parameters:

fm: fragment manager that will interact with this adapter

public FragmentPagerAdapter(FragmentManager fm, int behavior)

Constructor for FragmentPagerAdapter. If FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT is passed in, then only the current Fragment is in the state. All other fragments are capped at . If FragmentPagerAdapter.BEHAVIOR_SET_USER_VISIBLE_HINT is passed, all fragments are in the state and there will be callbacks to Fragment.setUserVisibleHint(boolean).

Parameters:

fm: fragment manager that will interact with this adapter
behavior: determines if only current fragments are in a resumed state

Methods

public abstract Fragment getItem(int position)

Return the Fragment associated with a specified position.

public void startUpdate(View container)

Deprecated: Use PagerAdapter.startUpdate(ViewGroup)

Called when a change in the shown pages is going to start being made.

Parameters:

container: The containing View which is displaying this adapter's page views.

public java.lang.Object instantiateItem(View container, int position)

Deprecated: Use PagerAdapter.instantiateItem(ViewGroup, int)

Create the page for the given position. The adapter is responsible for adding the view to the container given here, although it only must ensure this is done by the time it returns from PagerAdapter.finishUpdate(ViewGroup).

Parameters:

container: The containing View in which the page will be shown.
position: The page position to be instantiated.

Returns:

Returns an Object representing the new page. This does not need to be a View, but can be some other container of the page.

public void destroyItem(View container, int position, java.lang.Object object)

Deprecated: Use PagerAdapter.destroyItem(ViewGroup, int, Object)

Remove a page for the given position. The adapter is responsible for removing the view from its container, although it only must ensure this is done by the time it returns from PagerAdapter.finishUpdate(View).

Parameters:

container: The containing View from which the page will be removed.
position: The page position to be removed.
object: The same object that was returned by PagerAdapter.instantiateItem(View, int).

public void setPrimaryItem(View container, int position, java.lang.Object object)

Deprecated: Use PagerAdapter.setPrimaryItem(ViewGroup, int, Object)

Called to inform the adapter of which item is currently considered to be the "primary", that is the one show to the user as the current page.

Parameters:

container: The containing View from which the page will be removed.
position: The page position that is now the primary.
object: The same object that was returned by PagerAdapter.instantiateItem(View, int).

public void finishUpdate(View container)

Deprecated: Use PagerAdapter.finishUpdate(ViewGroup)

Called when the a change in the shown pages has been completed. At this point you must ensure that all of the pages have actually been added or removed from the container as appropriate.

Parameters:

container: The containing View which is displaying this adapter's page views.

public abstract boolean isViewFromObject(View view, java.lang.Object object)

Determines whether a page View is associated with a specific key object as returned by PagerAdapter.instantiateItem(ViewGroup, int). This method is required for a PagerAdapter to function properly.

Parameters:

view: Page View to check for association with object
object: Object to check for association with view

Returns:

true if view is associated with the key object object

public Parcelable saveState()

Save any instance state associated with this adapter and its pages that should be restored if the current UI state needs to be reconstructed.

Returns:

Saved state for this adapter

public void restoreState(Parcelable state, java.lang.ClassLoader loader)

Restore any instance state associated with this adapter and its pages that was previously saved by PagerAdapter.saveState().

Parameters:

state: State previously saved by a call to PagerAdapter.saveState()
loader: A ClassLoader that should be used to instantiate any restored objects

public long getItemId(int position)

Return a unique identifier for the item at the given position.

The default implementation returns the given position. Subclasses should override this method if the positions of items can change.

Parameters:

position: Position within this adapter

Returns:

Unique identifier for the item at position

Source

/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.fragment.app;

import android.os.Parcelable;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager.widget.PagerAdapter;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Implementation of {@link PagerAdapter} that
 * represents each page as a {@link Fragment} that is persistently
 * kept in the fragment manager as long as the user can return to the page.
 *
 * <p>This version of the pager is best for use when there are a handful of
 * typically more static fragments to be paged through, such as a set of tabs.
 * The fragment of each page the user visits will be kept in memory, though its
 * view hierarchy may be destroyed when not visible.  This can result in using
 * a significant amount of memory since fragment instances can hold on to an
 * arbitrary amount of state.  For larger sets of pages, consider
 * {@link FragmentStatePagerAdapter}.
 *
 * <p>When using FragmentPagerAdapter the host ViewPager must have a
 * valid ID set.</p>
 *
 * <p>Subclasses only need to implement {@link #getItem(int)}
 * and {@link #getCount()} to have a working adapter.
 *
 * <p>Here is an example implementation of a pager containing fragments of
 * lists:
 *
 * {@sample frameworks/support/samples/Support4Demos/src/main/java/com/example/android/supportv4/app/FragmentPagerSupport.java
 *      complete}
 *
 * <p>The <code>R.layout.fragment_pager</code> resource of the top-level fragment is:
 *
 * {@sample frameworks/support/samples/Support4Demos/src/main/res/layout/fragment_pager.xml
 *      complete}
 *
 * <p>The <code>R.layout.fragment_pager_list</code> resource containing each
 * individual fragment's layout is:
 *
 * {@sample frameworks/support/samples/Support4Demos/src/main/res/layout/fragment_pager_list.xml
 *      complete}
 *
 * @deprecated Switch to {@link androidx.viewpager2.widget.ViewPager2} and use
 * {@link androidx.viewpager2.adapter.FragmentStateAdapter} instead.
 */
@Deprecated
public abstract class FragmentPagerAdapter extends PagerAdapter {
    private static final String TAG = "FragmentPagerAdapter";
    private static final boolean DEBUG = false;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({BEHAVIOR_SET_USER_VISIBLE_HINT, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT})
    private @interface Behavior { }

    /**
     * Indicates that {@link Fragment#setUserVisibleHint(boolean)} will be called when the current
     * fragment changes.
     *
     * @deprecated This behavior relies on the deprecated
     * {@link Fragment#setUserVisibleHint(boolean)} API. Use
     * {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} to switch to its replacement,
     * {@link FragmentTransaction#setMaxLifecycle}.
     * @see #FragmentPagerAdapter(FragmentManager, int)
     */
    @Deprecated
    public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0;

    /**
     * Indicates that only the current fragment will be in the {@link Lifecycle.State#RESUMED}
     * state. All other Fragments are capped at {@link Lifecycle.State#STARTED}.
     *
     * @see #FragmentPagerAdapter(FragmentManager, int)
     */
    public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1;

    private final FragmentManager mFragmentManager;
    private final int mBehavior;
    private FragmentTransaction mCurTransaction = null;
    private Fragment mCurrentPrimaryItem = null;
    private boolean mExecutingFinishUpdate;

    /**
     * Constructor for {@link FragmentPagerAdapter} that sets the fragment manager for the adapter.
     * This is the equivalent of calling {@link #FragmentPagerAdapter(FragmentManager, int)} and
     * passing in {@link #BEHAVIOR_SET_USER_VISIBLE_HINT}.
     *
     * <p>Fragments will have {@link Fragment#setUserVisibleHint(boolean)} called whenever the
     * current Fragment changes.</p>
     *
     * @param fm fragment manager that will interact with this adapter
     * @deprecated use {@link #FragmentPagerAdapter(FragmentManager, int)} with
     * {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT}
     */
    @Deprecated
    public FragmentPagerAdapter(@NonNull FragmentManager fm) {
        this(fm, BEHAVIOR_SET_USER_VISIBLE_HINT);
    }

    /**
     * Constructor for {@link FragmentPagerAdapter}.
     *
     * If {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} is passed in, then only the current
     * Fragment is in the {@link Lifecycle.State#RESUMED} state. All other fragments are capped at
     * {@link Lifecycle.State#STARTED}. If {@link #BEHAVIOR_SET_USER_VISIBLE_HINT} is passed, all
     * fragments are in the {@link Lifecycle.State#RESUMED} state and there will be callbacks to
     * {@link Fragment#setUserVisibleHint(boolean)}.
     *
     * @param fm fragment manager that will interact with this adapter
     * @param behavior determines if only current fragments are in a resumed state
     */
    public FragmentPagerAdapter(@NonNull FragmentManager fm,
            @Behavior int behavior) {
        mFragmentManager = fm;
        mBehavior = behavior;
    }

    /**
     * Return the Fragment associated with a specified position.
     */
    @NonNull
    public abstract Fragment getItem(int position);

    @Override
    public void startUpdate(@NonNull ViewGroup container) {
        if (container.getId() == View.NO_ID) {
            throw new IllegalStateException("ViewPager with adapter " + this
                    + " requires a view id");
        }
    }

    @SuppressWarnings({"ReferenceEquality", "deprecation"})
    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }

        final long itemId = getItemId(position);

        // Do we already have this fragment?
        String name = makeFragmentName(container.getId(), itemId);
        Fragment fragment = mFragmentManager.findFragmentByTag(name);
        if (fragment != null) {
            if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
            mCurTransaction.attach(fragment);
        } else {
            fragment = getItem(position);
            if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
            mCurTransaction.add(container.getId(), fragment,
                    makeFragmentName(container.getId(), itemId));
        }
        if (fragment != mCurrentPrimaryItem) {
            fragment.setMenuVisibility(false);
            if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
                mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);
            } else {
                fragment.setUserVisibleHint(false);
            }
        }

        return fragment;
    }

    // TODO(b/141958824): Suppressed during upgrade to AGP 3.6.
    @SuppressWarnings("ReferenceEquality")
    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        Fragment fragment = (Fragment) object;

        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
        if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
                + " v=" + fragment.getView());
        mCurTransaction.detach(fragment);
        if (fragment.equals(mCurrentPrimaryItem)) {
            mCurrentPrimaryItem = null;
        }
    }

    @SuppressWarnings({"ReferenceEquality", "deprecation"})
    @Override
    public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        Fragment fragment = (Fragment)object;
        if (fragment != mCurrentPrimaryItem) {
            if (mCurrentPrimaryItem != null) {
                mCurrentPrimaryItem.setMenuVisibility(false);
                if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
                    if (mCurTransaction == null) {
                        mCurTransaction = mFragmentManager.beginTransaction();
                    }
                    mCurTransaction.setMaxLifecycle(mCurrentPrimaryItem, Lifecycle.State.STARTED);
                } else {
                    mCurrentPrimaryItem.setUserVisibleHint(false);
                }
            }
            fragment.setMenuVisibility(true);
            if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
                if (mCurTransaction == null) {
                    mCurTransaction = mFragmentManager.beginTransaction();
                }
                mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.RESUMED);
            } else {
                fragment.setUserVisibleHint(true);
            }

            mCurrentPrimaryItem = fragment;
        }
    }

    @Override
    public void finishUpdate(@NonNull ViewGroup container) {
        if (mCurTransaction != null) {
            // We drop any transactions that attempt to be committed
            // from a re-entrant call to finishUpdate(). We need to
            // do this as a workaround for Robolectric running measure/layout
            // calls inline rather than allowing them to be posted
            // as they would on a real device.
            if (!mExecutingFinishUpdate) {
                try {
                    mExecutingFinishUpdate = true;
                    mCurTransaction.commitNowAllowingStateLoss();
                } finally {
                    mExecutingFinishUpdate = false;
                }
            }
            mCurTransaction = null;
        }
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        return ((Fragment)object).getView() == view;
    }

    @Override
    @Nullable
    public Parcelable saveState() {
        return null;
    }

    @Override
    public void restoreState(@Nullable Parcelable state, @Nullable ClassLoader loader) {
    }

    /**
     * Return a unique identifier for the item at the given position.
     *
     * <p>The default implementation returns the given position.
     * Subclasses should override this method if the positions of items can change.</p>
     *
     * @param position Position within this adapter
     * @return Unique identifier for the item at position
     */
    public long getItemId(int position) {
        return position;
    }

    private static String makeFragmentName(int viewId, long id) {
        return "android:switcher:" + viewId + ":" + id;
    }
}