Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c801768e authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Integrate Loader support in to Activity/Fragment.

Introduces a new LoaderManager class that takes care of
most of what LoaderManagingFragment does.  Every Fragment
and Activity can have one instance of this class.  In the
future, the instance will be retained across config changes.

Also various other cleanups and improvement.

Change-Id: I3dfb406dca46bda7f5acb3c722efcbfb8d0aa9ba
parent 2951c6d0
Loading
Loading
Loading
Loading
+151 −13
Original line number Diff line number Diff line
@@ -20509,6 +20509,17 @@
 visibility="public"
>
</method>
<method name="getLoaderManager"
 return="android.app.LoaderManager"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getLocalClassName"
 return="java.lang.String"
 abstract="false"
@@ -20760,6 +20771,19 @@
<parameter name="data" type="android.content.Intent">
</parameter>
</method>
<method name="onAttachFragment"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="fragment" type="android.app.Fragment">
</parameter>
</method>
<method name="onAttachedToWindow"
 return="void"
 abstract="false"
@@ -25977,6 +26001,17 @@
 visibility="public"
>
</method>
<method name="getLoaderManager"
 return="android.app.LoaderManager"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getRetainInstance"
 return="boolean"
 abstract="false"
@@ -26054,6 +26089,19 @@
 visibility="public"
>
</method>
<method name="onActivityCreated"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="savedInstanceState" type="android.os.Bundle">
</parameter>
</method>
<method name="onActivityResult"
 return="void"
 abstract="false"
@@ -26313,19 +26361,6 @@
<parameter name="menu" type="android.view.Menu">
</parameter>
</method>
<method name="onReady"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="savedInstanceState" type="android.os.Bundle">
</parameter>
</method>
<method name="onResume"
 return="void"
 abstract="false"
@@ -28436,6 +28471,96 @@
</parameter>
</method>
</class>
<class name="LoaderManager"
 extends="java.lang.Object"
 abstract="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<method name="getLoader"
 return="android.content.Loader&lt;D&gt;"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="id" type="int">
</parameter>
</method>
<method name="startLoading"
 return="android.content.Loader&lt;D&gt;"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="id" type="int">
</parameter>
<parameter name="args" type="android.os.Bundle">
</parameter>
<parameter name="callback" type="android.app.LoaderManager.LoaderCallbacks&lt;D&gt;">
</parameter>
</method>
<method name="stopLoading"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="id" type="int">
</parameter>
</method>
</class>
<interface name="LoaderManager.LoaderCallbacks"
 abstract="true"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<method name="onCreateLoader"
 return="android.content.Loader&lt;D&gt;"
 abstract="true"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="id" type="int">
</parameter>
<parameter name="args" type="android.os.Bundle">
</parameter>
</method>
<method name="onLoadFinished"
 return="void"
 abstract="true"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="loader" type="android.content.Loader&lt;D&gt;">
</parameter>
<parameter name="data" type="D">
</parameter>
</method>
</interface>
<class name="LoaderManagingFragment"
 extends="android.app.Fragment"
 abstract="true"
@@ -174029,6 +174154,19 @@
<parameter name="key" type="int">
</parameter>
</method>
<method name="removeAt"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="index" type="int">
</parameter>
</method>
<method name="setValueAt"
 return="void"
 abstract="false"
+36 −7
Original line number Diff line number Diff line
@@ -649,6 +649,7 @@ public class Activity extends ContextThemeWrapper
        Object activity;
        HashMap<String, Object> children;
        ArrayList<Fragment> fragments;
        SparseArray<LoaderManager> loaders;
    }
    /* package */ NonConfigurationInstances mLastNonConfigurationInstances;
    
@@ -666,6 +667,9 @@ public class Activity extends ContextThemeWrapper

    final FragmentManager mFragments = new FragmentManager();
    
    SparseArray<LoaderManager> mAllLoaderManagers;
    LoaderManager mLoaderManager;
    
    private static final class ManagedCursor {
        ManagedCursor(Cursor cursor) {
            mCursor = cursor;
@@ -762,6 +766,29 @@ public class Activity extends ContextThemeWrapper
        return mWindow;
    }

    /**
     * Return the LoaderManager for this fragment, creating it if needed.
     */
    public LoaderManager getLoaderManager() {
        if (mLoaderManager != null) {
            return mLoaderManager;
        }
        mLoaderManager = getLoaderManager(-1, false);
        return mLoaderManager;
    }
    
    LoaderManager getLoaderManager(int index, boolean started) {
        if (mAllLoaderManagers == null) {
            mAllLoaderManagers = new SparseArray<LoaderManager>();
        }
        LoaderManager lm = mAllLoaderManagers.get(index);
        if (lm == null) {
            lm = new LoaderManager(started);
            mAllLoaderManagers.put(index, lm);
        }
        return lm;
    }
    
    /**
     * Calls {@link android.view.Window#getCurrentFocus} on the
     * Window of this Activity to return the currently focused view.
@@ -1518,6 +1545,14 @@ public class Activity extends ContextThemeWrapper
        return new BackStackEntry(mFragments);
    }
    
    /**
     * Called when a Fragment is being attached to this activity, immediately
     * after the call to its {@link Fragment#onAttach Fragment.onAttach()}
     * method and before {@link Fragment#onCreate Fragment.onCreate()}.
     */
    public void onAttachFragment(Fragment fragment) {
    }
    
    /**
     * Wrapper around
     * {@link ContentResolver#query(android.net.Uri , String[], String, String[], String)}
@@ -2060,13 +2095,6 @@ public class Activity extends ContextThemeWrapper
    }

    public void onContentChanged() {
        // First time content is available, let the fragment manager
        // attach all of the fragments to it.  Don't do this if the
        // activity is no longer attached (because it is being destroyed).
        if (mFragments.mCurState < Fragment.CONTENT
                && mFragments.mActivity != null) {
            mFragments.moveToState(Fragment.CONTENT, false);
        }
    }

    /**
@@ -4024,6 +4052,7 @@ public class Activity extends ContextThemeWrapper

    final void performCreate(Bundle icicle) {
        onCreate(icicle);
        mFragments.dispatchActivityCreated();
    }
    
    final void performStart() {
+59 −15
Original line number Diff line number Diff line
@@ -134,12 +134,12 @@ final class FragmentState implements Parcelable {
 * that can be placed in an {@link Activity}.
 */
public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener {
    private static final HashMap<String, Class> sClassMap =
            new HashMap<String, Class>();
    private static final HashMap<String, Class<?>> sClassMap =
            new HashMap<String, Class<?>>();
    
    static final int INITIALIZING = 0;     // Not yet created.
    static final int CREATED = 1;          // Created.
    static final int CONTENT = 2;       // View hierarchy content available.
    static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
    static final int STARTED = 3;          // Created and started, not resumed.
    static final int RESUMED = 4;          // Created started and resumed.
    
@@ -210,6 +210,17 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
    // The View generated for this fragment.
    View mView;
    
    LoaderManager mLoaderManager;
    boolean mStarted;
    
    /**
     * Default constructor.  <strong>Every</string> fragment must have an
     * empty constructor, so it can be instantiated when restoring its
     * activity's state.  It is strongly recommended that subclasses do not
     * have other constructors with parameters, since these constructors
     * will not be called when the fragment is re-instantiated; instead,
     * retrieve such parameters from the activity in {@link #onAttach(Activity)}.
     */
    public Fragment() {
    }

@@ -217,7 +228,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
            throws NoSuchMethodException, ClassNotFoundException,
            IllegalArgumentException, InstantiationException,
            IllegalAccessException, InvocationTargetException {
        Class clazz = sClassMap.get(fname);
        Class<?> clazz = sClassMap.get(fname);

        if (clazz == null) {
            // Class not found in the cache, see if it's real, and try to add it
@@ -350,7 +361,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
     * will be, because the fragment is being detached from its current activity).
     * <li> {@link #onCreate(Bundle)} will not be called since the fragment
     * is not being re-created.
     * <li> {@link #onAttach(Activity)} and {@link #onReady(Bundle)} <b>will</b>
     * <li> {@link #onAttach(Activity)} and {@link #onActivityCreated(Bundle)} <b>will</b>
     * still be called.
     * </ul>
     */
@@ -378,6 +389,17 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
        }
    }
    
    /**
     * Return the LoaderManager for this fragment, creating it if needed.
     */
    public LoaderManager getLoaderManager() {
        if (mLoaderManager != null) {
            return mLoaderManager;
        }
        mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted);
        return mLoaderManager;
    }
    
    /**
     * Call {@link Activity#startActivity(Intent)} on the fragment's
     * containing Activity.
@@ -446,7 +468,15 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
    
    /**
     * Called to do initial creation of a fragment.  This is called after
     * {@link #onAttach(Activity)} and before {@link #onReady(Bundle)}.
     * {@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.
     */
@@ -458,7 +488,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
     * 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 #onReady(Bundle)}.
     * {@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.
@@ -483,16 +513,19 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
    }
    
    /**
     * Called when the activity is ready for the fragment to run.  This is
     * most useful for fragments that use {@link #setRetainInstance(boolean)}
     * instance, as this tells the fragment when it is fully associated with
     * 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 #onStart()}.
     * 
     * @param savedInstanceState If the fragment is being re-created from
     * a previous saved state, this is the state.
     */
    public void onReady(Bundle savedInstanceState) {
    public void onActivityCreated(Bundle savedInstanceState) {
        mCalled = true;
    }
    
@@ -503,6 +536,10 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
     */
    public void onStart() {
        mCalled = true;
        mStarted = true;
        if (mLoaderManager != null) {
            mLoaderManager.doStart();
        }
    }
    
    /**
@@ -538,6 +575,10 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
     */
    public void onStop() {
        mCalled = true;
        mStarted = false;
        if (mLoaderManager != null) {
            mLoaderManager.doStop();
        }
    }
    
    public void onLowMemory() {
@@ -561,6 +602,9 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
     */
    public void onDestroy() {
        mCalled = true;
        if (mLoaderManager != null) {
            mLoaderManager.doDestroy();
        }
    }

    /**
+11 −6
Original line number Diff line number Diff line
@@ -162,6 +162,7 @@ public class FragmentManager {
                        throw new SuperNotCalledException("Fragment " + f
                                + " did not call through to super.onAttach()");
                    }
                    mActivity.onAttachFragment(f);
                    
                    if (!f.mRetaining) {
                        f.mCalled = false;
@@ -216,15 +217,15 @@ public class FragmentManager {
                        }
                        
                        f.mCalled = false;
                        f.onReady(f.mSavedFragmentState);
                        f.onActivityCreated(f.mSavedFragmentState);
                        if (!f.mCalled) {
                            throw new SuperNotCalledException("Fragment " + f
                                    + " did not call through to super.onReady()");
                        }
                        f.mSavedFragmentState = null;
                    }
                case Fragment.CONTENT:
                    if (newState > Fragment.CONTENT) {
                case Fragment.ACTIVITY_CREATED:
                    if (newState > Fragment.ACTIVITY_CREATED) {
                        if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                        f.mCalled = false;
                        f.onStart();
@@ -266,8 +267,8 @@ public class FragmentManager {
                                    + " did not call through to super.onStop()");
                        }
                    }
                case Fragment.CONTENT:
                    if (newState < Fragment.CONTENT) {
                case Fragment.ACTIVITY_CREATED:
                    if (newState < Fragment.ACTIVITY_CREATED) {
                        if (DEBUG) Log.v(TAG, "movefrom CONTENT: " + f);
                        if (f.mView != null) {
                            f.mCalled = false;
@@ -783,6 +784,10 @@ public class FragmentManager {
        moveToState(Fragment.CREATED, false);
    }
    
    public void dispatchActivityCreated() {
        moveToState(Fragment.ACTIVITY_CREATED, false);
    }
    
    public void dispatchStart() {
        moveToState(Fragment.STARTED, false);
    }
@@ -796,7 +801,7 @@ public class FragmentManager {
    }
    
    public void dispatchStop() {
        moveToState(Fragment.CONTENT, false);
        moveToState(Fragment.ACTIVITY_CREATED, false);
    }
    
    public void dispatchDestroy() {
+3 −7
Original line number Diff line number Diff line
@@ -160,7 +160,6 @@ public class ListFragment extends Fragment {
    TextView mStandardEmptyView;
    View mProgressContainer;
    View mListContainer;
    boolean mSetEmptyView;
    boolean mListShown;

    public ListFragment() {
@@ -185,8 +184,8 @@ public class ListFragment extends Fragment {
     * Attach to list view once Fragment is ready to run.
     */
    @Override
    public void onReady(Bundle savedInstanceState) {
        super.onReady(savedInstanceState);
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        ensureList();
    }

@@ -269,11 +268,8 @@ public class ListFragment extends Fragment {
        if (mStandardEmptyView == null) {
            throw new IllegalStateException("Can't be used with a custom content view");
        }
        if (!mSetEmptyView) {
            mSetEmptyView = true;
        mList.setEmptyView(mStandardEmptyView);
    }
    }
    
    /**
     * Control whether the list is being displayed.  You can make it not
Loading