FileDocCategorySizeDatePackage
FragmentActivity.javaAPI DocAndroid 5.1 API31625Thu Mar 12 22:22:56 GMT 2015android.support.v4.app

FragmentActivity

public class FragmentActivity extends android.app.Activity
Base class for activities that want to use the support-based {@link android.support.v4.app.Fragment} and {@link android.support.v4.content.Loader} APIs.

When using this class as opposed to new platform's built-in fragment and loader support, you must use the {@link #getSupportFragmentManager()} and {@link #getSupportLoaderManager()} methods respectively to access those features.

Note: If you want to implement an activity that includes an action bar, you should instead use the {@link android.support.v7.app.ActionBarActivity} class, which is a subclass of this one, so allows you to use {@link android.support.v4.app.Fragment} APIs on API level 7 and higher.

Known limitations:

  • When using the <fragment> tag, this implementation can not use the parent view's ID as the new fragment's ID. You must explicitly specify an ID (or tag) in the <fragment>.

  • Prior to Honeycomb (3.0), an activity's state was saved before pausing. Fragments are a significant amount of new state, and dynamic enough that one often wants them to change between pausing and stopping. These classes throw an exception if you try to change the fragment state after it has been saved, to avoid accidental loss of UI state. However this is too restrictive prior to Honeycomb, where the state is saved before pausing. To address this, when running on platforms prior to Honeycomb an exception will not be thrown if you change fragments between the state save and the activity being stopped. This means that in some cases if the activity is restored from its last saved state, this may be a snapshot slightly before what the user last saw.

Fields Summary
private static final String
TAG
static final String
FRAGMENTS_TAG
private static final int
HONEYCOMB
static final int
MSG_REALLY_STOPPED
static final int
MSG_RESUME_PENDING
final android.os.Handler
mHandler
final FragmentManagerImpl
mFragments
final FragmentContainer
mContainer
boolean
mCreated
boolean
mResumed
boolean
mStopped
boolean
mReallyStopped
boolean
mRetaining
boolean
mOptionsMenuInvalidated
boolean
mCheckedForLoaderManager
boolean
mLoadersStarted
android.support.v4.util.SimpleArrayMap
mAllLoaderManagers
LoaderManagerImpl
mLoaderManager
Constructors Summary
Methods Summary
voiddoReallyStop(boolean retaining)

        if (!mReallyStopped) {
            mReallyStopped = true;
            mRetaining = retaining;
            mHandler.removeMessages(MSG_REALLY_STOPPED);
            onReallyStop();
        }
    
public voiddump(java.lang.String prefix, java.io.FileDescriptor fd, java.io.PrintWriter writer, java.lang.String[] args)
Print the Activity's state into the given stream. This gets invoked if you run "adb shell dumpsys activity ".

param
prefix Desired prefix to prepend at each line of output.
param
fd The raw file descriptor that the dump is being sent to.
param
writer The PrintWriter to which you should dump your state. This will be closed for you after you return.
param
args additional arguments to the dump request.

        if (android.os.Build.VERSION.SDK_INT >= HONEYCOMB) {
            // XXX This can only work if we can call the super-class impl. :/
            //ActivityCompatHoneycomb.dump(this, prefix, fd, writer, args);
        }
        writer.print(prefix); writer.print("Local FragmentActivity ");
                writer.print(Integer.toHexString(System.identityHashCode(this)));
                writer.println(" State:");
        String innerPrefix = prefix + "  ";
        writer.print(innerPrefix); writer.print("mCreated=");
                writer.print(mCreated); writer.print("mResumed=");
                writer.print(mResumed); writer.print(" mStopped=");
                writer.print(mStopped); writer.print(" mReallyStopped=");
                writer.println(mReallyStopped);
        writer.print(innerPrefix); writer.print("mLoadersStarted=");
                writer.println(mLoadersStarted);
        if (mLoaderManager != null) {
            writer.print(prefix); writer.print("Loader Manager ");
                    writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager)));
                    writer.println(":");
            mLoaderManager.dump(prefix + "  ", fd, writer, args);
        }
        mFragments.dump(prefix, fd, writer, args);
        writer.print(prefix); writer.println("View Hierarchy:");
        dumpViewHierarchy(prefix + "  ", writer, getWindow().getDecorView());
    
private voiddumpViewHierarchy(java.lang.String prefix, java.io.PrintWriter writer, android.view.View view)

        writer.print(prefix);
        if (view == null) {
            writer.println("null");
            return;
        }
        writer.println(viewToString(view));
        if (!(view instanceof ViewGroup)) {
            return;
        }
        ViewGroup grp = (ViewGroup)view;
        final int N = grp.getChildCount();
        if (N <= 0) {
            return;
        }
        prefix = prefix + "  ";
        for (int i=0; i<N; i++) {
            dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
        }
    
public java.lang.ObjectgetLastCustomNonConfigurationInstance()
Return the value previously returned from {@link #onRetainCustomNonConfigurationInstance()}.

        NonConfigurationInstances nc = (NonConfigurationInstances)
                getLastNonConfigurationInstance();
        return nc != null ? nc.custom : null;
    
LoaderManagerImplgetLoaderManager(java.lang.String who, boolean started, boolean create)

        if (mAllLoaderManagers == null) {
            mAllLoaderManagers = new SimpleArrayMap<String, LoaderManagerImpl>();
        }
        LoaderManagerImpl lm = mAllLoaderManagers.get(who);
        if (lm == null) {
            if (create) {
                lm = new LoaderManagerImpl(who, this, started);
                mAllLoaderManagers.put(who, lm);
            }
        } else {
            lm.updateActivity(this);
        }
        return lm;
    
public FragmentManagergetSupportFragmentManager()
Return the FragmentManager for interacting with fragments associated with this activity.

        return mFragments;
    
public LoaderManagergetSupportLoaderManager()
Return the LoaderManager for this fragment, creating it if needed.

        if (mLoaderManager != null) {
            return mLoaderManager;
        }
        mCheckedForLoaderManager = true;
        mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);
        return mLoaderManager;
    
voidinvalidateSupportFragment(java.lang.String who)

        //Log.v(TAG, "invalidateSupportFragment: who=" + who);
        if (mAllLoaderManagers != null) {
            LoaderManagerImpl lm = mAllLoaderManagers.get(who);
            if (lm != null && !lm.mRetaining) {
                lm.doDestroy();
                mAllLoaderManagers.remove(who);
            }
        }
    
protected voidonActivityResult(int requestCode, int resultCode, android.content.Intent data)
Dispatch incoming result to the correct fragment.

    
    
    // ------------------------------------------------------------------------
    // HOOKS INTO ACTIVITY
    // ------------------------------------------------------------------------
    
                
    
            
        mFragments.noteStateNotSaved();
        int index = requestCode>>16;
        if (index != 0) {
            index--;
            if (mFragments.mActive == null || index < 0 || index >= mFragments.mActive.size()) {
                Log.w(TAG, "Activity result fragment index out of range: 0x"
                        + Integer.toHexString(requestCode));
                return;
            }
            Fragment frag = mFragments.mActive.get(index);
            if (frag == null) {
                Log.w(TAG, "Activity result no fragment exists for index: 0x"
                        + Integer.toHexString(requestCode));
            } else {
                frag.onActivityResult(requestCode&0xffff, resultCode, data);
            }
            return;
        }
        
        super.onActivityResult(requestCode, resultCode, data);
    
public voidonAttachFragment(Fragment fragment)
Called when a fragment is attached to the activity.

    
public voidonBackPressed()
Take care of popping the fragment back stack or finishing the activity as appropriate.

        if (!mFragments.popBackStackImmediate()) {
            supportFinishAfterTransition();
        }
    
public voidonConfigurationChanged(android.content.res.Configuration newConfig)
Dispatch configuration change to all fragments.

        super.onConfigurationChanged(newConfig);
        mFragments.dispatchConfigurationChanged(newConfig);
    
protected voidonCreate(android.os.Bundle savedInstanceState)
Perform initialization of all fragments and loaders.

        mFragments.attachActivity(this, mContainer, null);
        // Old versions of the platform didn't do this!
        if (getLayoutInflater().getFactory() == null) {
            getLayoutInflater().setFactory(this);
        }
        
        super.onCreate(savedInstanceState);
        
        NonConfigurationInstances nc = (NonConfigurationInstances)
                getLastNonConfigurationInstance();
        if (nc != null) {
            mAllLoaderManagers = nc.loaders;
        }
        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
        }
        mFragments.dispatchCreate();
    
public booleanonCreatePanelMenu(int featureId, android.view.Menu menu)
Dispatch to Fragment.onCreateOptionsMenu().

        if (featureId == Window.FEATURE_OPTIONS_PANEL) {
            boolean show = super.onCreatePanelMenu(featureId, menu);
            show |= mFragments.dispatchCreateOptionsMenu(menu, getMenuInflater());
            if (android.os.Build.VERSION.SDK_INT >= HONEYCOMB) {
                return show;
            }
            // Prior to Honeycomb, the framework can't invalidate the options
            // menu, so we must always say we have one in case the app later
            // invalidates it and needs to have it shown.
            return true;
        }
        return super.onCreatePanelMenu(featureId, menu);
    
public android.view.ViewonCreateView(java.lang.String name, android.content.Context context, android.util.AttributeSet attrs)
Add support for inflating the <fragment> tag.

        if (!"fragment".equals(name)) {
            return super.onCreateView(name, context, attrs);
        }

        final View v = mFragments.onCreateView(name, context, attrs);
        if (v == null) {
            return super.onCreateView(name, context, attrs);
        }
        return v;
    
protected voidonDestroy()
Destroy all fragments and loaders.

        super.onDestroy();

        doReallyStop(false);

        mFragments.dispatchDestroy();
        if (mLoaderManager != null) {
            mLoaderManager.doDestroy();
        }
    
public booleanonKeyDown(int keyCode, android.view.KeyEvent event)
Take care of calling onBackPressed() for pre-Eclair platforms.

        if (android.os.Build.VERSION.SDK_INT < 5 /* ECLAIR */
                && keyCode == KeyEvent.KEYCODE_BACK
                && event.getRepeatCount() == 0) {
            // Take care of calling this method on earlier versions of
            // the platform where it doesn't exist.
            onBackPressed();
            return true;
        }

        return super.onKeyDown(keyCode, event);
    
public voidonLowMemory()
Dispatch onLowMemory() to all fragments.

        super.onLowMemory();
        mFragments.dispatchLowMemory();
    
public booleanonMenuItemSelected(int featureId, android.view.MenuItem item)
Dispatch context and options menu to fragments.

        if (super.onMenuItemSelected(featureId, item)) {
            return true;
        }
        
        switch (featureId) {
            case Window.FEATURE_OPTIONS_PANEL:
                return mFragments.dispatchOptionsItemSelected(item);
                
            case Window.FEATURE_CONTEXT_MENU:
                return mFragments.dispatchContextItemSelected(item);

            default:
                return false;
        }
    
protected voidonNewIntent(android.content.Intent intent)
Handle onNewIntent() to inform the fragment manager that the state is not saved. If you are handling new intents and may be making changes to the fragment state, you want to be sure to call through to the super-class here first. Otherwise, if your state is saved but the activity is not stopped, you could get an onNewIntent() call which happens before onResume() and trying to perform fragment operations at that point will throw IllegalStateException because the fragment manager thinks the state is still saved.

        super.onNewIntent(intent);
        mFragments.noteStateNotSaved();
    
public voidonPanelClosed(int featureId, android.view.Menu menu)
Call onOptionsMenuClosed() on fragments.

        switch (featureId) {
            case Window.FEATURE_OPTIONS_PANEL:
                mFragments.dispatchOptionsMenuClosed(menu);
                break;
        }
        super.onPanelClosed(featureId, menu);
    
protected voidonPause()
Dispatch onPause() to fragments.

        super.onPause();
        mResumed = false;
        if (mHandler.hasMessages(MSG_RESUME_PENDING)) {
            mHandler.removeMessages(MSG_RESUME_PENDING);
            onResumeFragments();
        }
        mFragments.dispatchPause();
    
protected voidonPostResume()
Dispatch onResume() to fragments.

        super.onPostResume();
        mHandler.removeMessages(MSG_RESUME_PENDING);
        onResumeFragments();
        mFragments.execPendingActions();
    
protected booleanonPrepareOptionsPanel(android.view.View view, android.view.Menu menu)

hide

        return super.onPreparePanel(Window.FEATURE_OPTIONS_PANEL, view, menu);
    
public booleanonPreparePanel(int featureId, android.view.View view, android.view.Menu menu)
Dispatch onPrepareOptionsMenu() to fragments.

        if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) {
            if (mOptionsMenuInvalidated) {
                mOptionsMenuInvalidated = false;
                menu.clear();
                onCreatePanelMenu(featureId, menu);
            }
            boolean goforit = onPrepareOptionsPanel(view, menu);
            goforit |= mFragments.dispatchPrepareOptionsMenu(menu);
            return goforit;
        }
        return super.onPreparePanel(featureId, view, menu);
    
voidonReallyStop()
Pre-HC, we didn't have a way to determine whether an activity was being stopped for a config change or not until we saw onRetainNonConfigurationInstance() called after onStop(). However we need to know this, to know whether to retain fragments. This will tell us what we need to know.

        if (mLoadersStarted) {
            mLoadersStarted = false;
            if (mLoaderManager != null) {
                if (!mRetaining) {
                    mLoaderManager.doStop();
                } else {
                    mLoaderManager.doRetain();
                }
            }
        }

        mFragments.dispatchReallyStop();
    
protected voidonResume()
Dispatch onResume() to fragments. Note that for better inter-operation with older versions of the platform, at the point of this call the fragments attached to the activity are not resumed. This means that in some cases the previous state may still be saved, not allowing fragment transactions that modify the state. To correctly interact with fragments in their proper state, you should instead override {@link #onResumeFragments()}.

        super.onResume();
        mHandler.sendEmptyMessage(MSG_RESUME_PENDING);
        mResumed = true;
        mFragments.execPendingActions();
    
protected voidonResumeFragments()
This is the fragment-orientated version of {@link #onResume()} that you can override to perform operations in the Activity at the same point where its fragments are resumed. Be sure to always call through to the super-class.

        mFragments.dispatchResume();
    
public java.lang.ObjectonRetainCustomNonConfigurationInstance()
Use this instead of {@link #onRetainNonConfigurationInstance()}. Retrieve later with {@link #getLastCustomNonConfigurationInstance()}.

        return null;
    
public final java.lang.ObjectonRetainNonConfigurationInstance()
Retain all appropriate fragment and loader state. You can NOT override this yourself! Use {@link #onRetainCustomNonConfigurationInstance()} if you want to retain your own state.

        if (mStopped) {
            doReallyStop(true);
        }

        Object custom = onRetainCustomNonConfigurationInstance();

        ArrayList<Fragment> fragments = mFragments.retainNonConfig();
        boolean retainLoaders = false;
        if (mAllLoaderManagers != null) {
            // prune out any loader managers that were already stopped and so
            // have nothing useful to retain.
            final int N = mAllLoaderManagers.size();
            LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
            for (int i=N-1; i>=0; i--) {
                loaders[i] = mAllLoaderManagers.valueAt(i);
            }
            for (int i=0; i<N; i++) {
                LoaderManagerImpl lm = loaders[i];
                if (lm.mRetaining) {
                    retainLoaders = true;
                } else {
                    lm.doDestroy();
                    mAllLoaderManagers.remove(lm.mWho);
                }
            }
        }
        if (fragments == null && !retainLoaders && custom == null) {
            return null;
        }
        
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.activity = null;
        nci.custom = custom;
        nci.children = null;
        nci.fragments = fragments;
        nci.loaders = mAllLoaderManagers;
        return nci;
    
protected voidonSaveInstanceState(android.os.Bundle outState)
Save all appropriate fragment state.

        super.onSaveInstanceState(outState);
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
    
protected voidonStart()
Dispatch onStart() to all fragments. Ensure any created loaders are now started.

        super.onStart();

        mStopped = false;
        mReallyStopped = false;
        mHandler.removeMessages(MSG_REALLY_STOPPED);

        if (!mCreated) {
            mCreated = true;
            mFragments.dispatchActivityCreated();
        }

        mFragments.noteStateNotSaved();
        mFragments.execPendingActions();
        
        if (!mLoadersStarted) {
            mLoadersStarted = true;
            if (mLoaderManager != null) {
                mLoaderManager.doStart();
            } else if (!mCheckedForLoaderManager) {
                mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
                // the returned loader manager may be a new one, so we have to start it
                if ((mLoaderManager != null) && (!mLoaderManager.mStarted)) {
                    mLoaderManager.doStart();
                }
            }
            mCheckedForLoaderManager = true;
        }
        // NOTE: HC onStart goes here.
        
        mFragments.dispatchStart();
        if (mAllLoaderManagers != null) {
            final int N = mAllLoaderManagers.size();
            LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
            for (int i=N-1; i>=0; i--) {
                loaders[i] = mAllLoaderManagers.valueAt(i);
            }
            for (int i=0; i<N; i++) {
                LoaderManagerImpl lm = loaders[i];
                lm.finishRetain();
                lm.doReportStart();
            }
        }
    
protected voidonStop()
Dispatch onStop() to all fragments. Ensure all loaders are stopped.

        super.onStop();

        mStopped = true;
        mHandler.sendEmptyMessage(MSG_REALLY_STOPPED);
        
        mFragments.dispatchStop();
    
public voidsetEnterSharedElementCallback(SharedElementCallback callback)
When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity, android.view.View, String)} was used to start an Activity, callback will be called to handle shared elements on the launched Activity. This requires {@link Window#FEATURE_CONTENT_TRANSITIONS}.

param
callback Used to manipulate shared element transitions on the launched Activity.

        ActivityCompat.setEnterSharedElementCallback(this, callback);
    
public voidsetExitSharedElementCallback(SharedElementCallback listener)
When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity, android.view.View, String)} was used to start an Activity, listener will be called to handle shared elements on the launching Activity. Most calls will only come when returning from the started Activity. This requires {@link Window#FEATURE_CONTENT_TRANSITIONS}.

param
listener Used to manipulate shared element transitions on the launching Activity.

        ActivityCompat.setExitSharedElementCallback(this, listener);
    
public voidstartActivityForResult(android.content.Intent intent, int requestCode)
Modifies the standard behavior to allow results to be delivered to fragments. This imposes a restriction that requestCode be <= 0xffff.

        if (requestCode != -1 && (requestCode&0xffff0000) != 0) {
            throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
        }
        super.startActivityForResult(intent, requestCode);
    
public voidstartActivityFromFragment(Fragment fragment, android.content.Intent intent, int requestCode)
Called by Fragment.startActivityForResult() to implement its behavior.

        if (requestCode == -1) {
            super.startActivityForResult(intent, -1);
            return;
        }
        if ((requestCode&0xffff0000) != 0) {
            throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
        }
        super.startActivityForResult(intent, ((fragment.mIndex+1)<<16) + (requestCode&0xffff));
    
public voidsupportFinishAfterTransition()
Reverses the Activity Scene entry Transition and triggers the calling Activity to reverse its exit Transition. When the exit Transition completes, {@link #finish()} is called. If no entry Transition was used, finish() is called immediately and the Activity exit Transition is run.

On Android 4.4 or lower, this method only finishes the Activity with no special exit transition.

        ActivityCompat.finishAfterTransition(this);
    
public voidsupportInvalidateOptionsMenu()
Support library version of {@link Activity#invalidateOptionsMenu}.

Invalidate the activity's options menu. This will cause relevant presentations of the menu to fully update via calls to onCreateOptionsMenu and onPrepareOptionsMenu the next time the menu is requested.

        if (android.os.Build.VERSION.SDK_INT >= HONEYCOMB) {
            // If we are running on HC or greater, we can use the framework
            // API to invalidate the options menu.
            ActivityCompatHoneycomb.invalidateOptionsMenu(this);
            return;
        }

        // Whoops, older platform...  we'll use a hack, to manually rebuild
        // the options menu the next time it is prepared.
        mOptionsMenuInvalidated = true;
    
public voidsupportPostponeEnterTransition()
Support library version of {@link android.app.Activity#postponeEnterTransition()} that works only on API 21 and later.

        ActivityCompat.postponeEnterTransition(this);
    
public voidsupportStartPostponedEnterTransition()
Support library version of {@link android.app.Activity#startPostponedEnterTransition()} that only works with API 21 and later.

        ActivityCompat.startPostponedEnterTransition(this);
    
private static java.lang.StringviewToString(android.view.View view)

        StringBuilder out = new StringBuilder(128);
        out.append(view.getClass().getName());
        out.append('{");
        out.append(Integer.toHexString(System.identityHashCode(view)));
        out.append(' ");
        switch (view.getVisibility()) {
            case View.VISIBLE: out.append('V"); break;
            case View.INVISIBLE: out.append('I"); break;
            case View.GONE: out.append('G"); break;
            default: out.append('."); break;
        }
        out.append(view.isFocusable() ? 'F" : '.");
        out.append(view.isEnabled() ? 'E" : '.");
        out.append(view.willNotDraw() ? '." : 'D");
        out.append(view.isHorizontalScrollBarEnabled()? 'H" : '.");
        out.append(view.isVerticalScrollBarEnabled() ? 'V" : '.");
        out.append(view.isClickable() ? 'C" : '.");
        out.append(view.isLongClickable() ? 'L" : '.");
        out.append(' ");
        out.append(view.isFocused() ? 'F" : '.");
        out.append(view.isSelected() ? 'S" : '.");
        out.append(view.isPressed() ? 'P" : '.");
        out.append(' ");
        out.append(view.getLeft());
        out.append(',");
        out.append(view.getTop());
        out.append('-");
        out.append(view.getRight());
        out.append(',");
        out.append(view.getBottom());
        final int id = view.getId();
        if (id != View.NO_ID) {
            out.append(" #");
            out.append(Integer.toHexString(id));
            final Resources r = view.getResources();
            if (id != 0 && r != null) {
                try {
                    String pkgname;
                    switch (id&0xff000000) {
                        case 0x7f000000:
                            pkgname="app";
                            break;
                        case 0x01000000:
                            pkgname="android";
                            break;
                        default:
                            pkgname = r.getResourcePackageName(id);
                            break;
                    }
                    String typename = r.getResourceTypeName(id);
                    String entryname = r.getResourceEntryName(id);
                    out.append(" ");
                    out.append(pkgname);
                    out.append(":");
                    out.append(typename);
                    out.append("/");
                    out.append(entryname);
                } catch (Resources.NotFoundException e) {
                }
            }
        }
        out.append("}");
        return out.toString();