1cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn/*
2cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Copyright (C) 2011 The Android Open Source Project
3cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn *
4cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
5cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * you may not use this file except in compliance with the License.
6cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * You may obtain a copy of the License at
7cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn *
8cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
9cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn *
10cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
11cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
12cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * See the License for the specific language governing permissions and
14cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * limitations under the License.
15cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */
16cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
17cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornpackage android.support.v4.app;
18cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
19cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.app.Activity;
20cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.os.Bundle;
21cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.support.v4.content.Loader;
22cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.support.v4.util.DebugUtils;
23346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powellimport android.support.v4.util.SparseArrayCompat;
24cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.util.Log;
25cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
26cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport java.io.FileDescriptor;
27cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport java.io.PrintWriter;
28cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport java.lang.reflect.Modifier;
29cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
30cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn/**
31cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Static library support version of the framework's {@link android.app.LoaderManager}.
32cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Used to write apps that run on platforms prior to Android 3.0.  When running
33cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * on Android 3.0 or above, this implementation is still used; it does not try
34cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * to switch to the framework's implementation.  See the framework SDK
35cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * documentation for a class overview.
36cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn *
37cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * <p>Your activity must derive from {@link FragmentActivity} to use this.
38cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */
39cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornpublic abstract class LoaderManager {
40cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
41cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Callback interface for a client to interact with the manager.
42cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
43cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public interface LoaderCallbacks<D> {
44cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        /**
45cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * Instantiate and return a new Loader for the given ID.
46cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         *
47cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * @param id The ID whose loader is to be created.
48cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * @param args Any arguments supplied by the caller.
49cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * @return Return a new Loader instance that is ready to start loading.
50cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         */
51cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        public Loader<D> onCreateLoader(int id, Bundle args);
52cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
53cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        /**
54cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * Called when a previously created loader has finished its load.  Note
55cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * that normally an application is <em>not</em> allowed to commit fragment
56cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * transactions while in this call, since it can happen after an
57cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * activity's state is saved.  See {@link FragmentManager#beginTransaction()
58cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * FragmentManager.openTransaction()} for further discussion on this.
59cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         *
60cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * <p>This function is guaranteed to be called prior to the release of
61cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * the last data that was supplied for this Loader.  At this point
62cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * you should remove all use of the old data (since it will be released
63cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * soon), but should not do your own release of the data since its Loader
64cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * owns it and will take care of that.  The Loader will take care of
65cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * management of its data so you don't have to.  In particular:
66cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         *
67cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * <ul>
68cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * <li> <p>The Loader will monitor for changes to the data, and report
69cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * them to you through new calls here.  You should not monitor the
70cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * data yourself.  For example, if the data is a {@link android.database.Cursor}
71cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * and you place it in a {@link android.widget.CursorAdapter}, use
72cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * the {@link android.widget.CursorAdapter#CursorAdapter(android.content.Context,
73cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * android.database.Cursor, int)} constructor <em>without</em> passing
74cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * in either {@link android.widget.CursorAdapter#FLAG_AUTO_REQUERY}
75cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * or {@link android.widget.CursorAdapter#FLAG_REGISTER_CONTENT_OBSERVER}
76cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * (that is, use 0 for the flags argument).  This prevents the CursorAdapter
77cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * from doing its own observing of the Cursor, which is not needed since
78cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * when a change happens you will get a new Cursor throw another call
79cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * here.
80cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * <li> The Loader will release the data once it knows the application
81cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * is no longer using it.  For example, if the data is
82cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * a {@link android.database.Cursor} from a {@link android.content.CursorLoader},
83cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * you should not call close() on it yourself.  If the Cursor is being placed in a
84cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * {@link android.widget.CursorAdapter}, you should use the
85cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * {@link android.widget.CursorAdapter#swapCursor(android.database.Cursor)}
86cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * method so that the old Cursor is not closed.
87cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * </ul>
88cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         *
89cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * @param loader The Loader that has finished.
90cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * @param data The data generated by the Loader.
91cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         */
92cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        public void onLoadFinished(Loader<D> loader, D data);
93cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
94cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        /**
95cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * Called when a previously created loader is being reset, and thus
96cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * making its data unavailable.  The application should at this point
97cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * remove any references it has to the Loader's data.
98cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         *
99cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * @param loader The Loader that is being reset.
100cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         */
101cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        public void onLoaderReset(Loader<D> loader);
102cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
103cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
104cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
105cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Ensures a loader is initialized and active.  If the loader doesn't
106cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * already exist, one is created and (if the activity/fragment is currently
107cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * started) starts the loader.  Otherwise the last created
108cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * loader is re-used.
109cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
110cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>In either case, the given callback is associated with the loader, and
111cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * will be called as the loader state changes.  If at the point of call
112cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * the caller is in its started state, and the requested loader
113cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * already exists and has generated its data, then
114cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * callback {@link LoaderCallbacks#onLoadFinished} will
115cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * be called immediately (inside of this function), so you must be prepared
116cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * for this to happen.
117cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
118cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param id A unique identifier for this loader.  Can be whatever you want.
119cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Identifiers are scoped to a particular LoaderManager instance.
120cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param args Optional arguments to supply to the loader at construction.
121cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * If a loader already exists (a new one does not need to be created), this
122cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * parameter will be ignored and the last arguments continue to be used.
123cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param callback Interface the LoaderManager will call to report about
124cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * changes in the state of the loader.  Required.
125cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
126cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public abstract <D> Loader<D> initLoader(int id, Bundle args,
127cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            LoaderManager.LoaderCallbacks<D> callback);
128cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
129cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
130cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Starts a new or restarts an existing {@link android.content.Loader} in
131cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * this manager, registers the callbacks to it,
132cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * and (if the activity/fragment is currently started) starts loading it.
133cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * If a loader with the same id has previously been
134cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * started it will automatically be destroyed when the new loader completes
135cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * its work. The callback will be delivered before the old loader
136cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * is destroyed.
137cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
138cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param id A unique identifier for this loader.  Can be whatever you want.
139cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Identifiers are scoped to a particular LoaderManager instance.
140cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param args Optional arguments to supply to the loader at construction.
141cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param callback Interface the LoaderManager will call to report about
142cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * changes in the state of the loader.  Required.
143cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
144cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public abstract <D> Loader<D> restartLoader(int id, Bundle args,
145cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            LoaderManager.LoaderCallbacks<D> callback);
146cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
147cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
148cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Stops and removes the loader with the given ID.  If this loader
149cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * had previously reported data to the client through
150cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * {@link LoaderCallbacks#onLoadFinished(Loader, Object)}, a call
151cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * will be made to {@link LoaderCallbacks#onLoaderReset(Loader)}.
152cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
153cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public abstract void destroyLoader(int id);
154cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
155cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
156cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Return the Loader with the given id or null if no matching Loader
157cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * is found.
158cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
159cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public abstract <D> Loader<D> getLoader(int id);
160cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
161cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
162cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Print the LoaderManager's state into the given stream.
163cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
164cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param prefix Text to print at the front of each line.
165cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param fd The raw file descriptor that the dump is being sent to.
166cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param writer A PrintWriter to which the dump is to be set.
167cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param args Additional arguments to the dump request.
168cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
169cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
170cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
171cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
172cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Control whether the framework's internal loader manager debugging
173cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * logs are turned on.  If enabled, you will see output in logcat as
174cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * the framework performs loader operations.
175cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
176cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public static void enableDebugLogging(boolean enabled) {
177cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        LoaderManagerImpl.DEBUG = enabled;
178cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
179abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell
180abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell    /**
181abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell     * Returns true if any loaders managed are currently running and have not
182abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell     * returned data to the application yet.
183abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell     */
184abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell    public boolean hasRunningLoaders() { return false; }
185cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn}
186cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
187cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornclass LoaderManagerImpl extends LoaderManager {
188cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    static final String TAG = "LoaderManager";
189cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    static boolean DEBUG = false;
190cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
191cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    // These are the currently active loaders.  A loader is here
192cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    // from the time its load is started until it has been explicitly
193cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    // stopped or restarted by the application.
194346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell    final SparseArrayCompat<LoaderInfo> mLoaders = new SparseArrayCompat<LoaderInfo>();
195cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
196cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    // These are previously run loaders.  This list is maintained internally
197cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    // to avoid destroying a loader while an application is still using it.
198cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    // It allows an application to restart a loader, but continue using its
199cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    // previously run loader until the new loader's data is available.
200346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell    final SparseArrayCompat<LoaderInfo> mInactiveLoaders = new SparseArrayCompat<LoaderInfo>();
201cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
2020adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn    final String mWho;
2030adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn
204cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    FragmentActivity mActivity;
205cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    boolean mStarted;
206cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    boolean mRetaining;
207cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    boolean mRetainingStarted;
208cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
209cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    boolean mCreatingLoader;
210cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
211cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    final class LoaderInfo implements Loader.OnLoadCompleteListener<Object> {
212cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        final int mId;
213cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        final Bundle mArgs;
214cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        LoaderManager.LoaderCallbacks<Object> mCallbacks;
215cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        Loader<Object> mLoader;
216cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        boolean mHaveData;
217cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        boolean mDeliveredData;
218cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        Object mData;
219cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        boolean mStarted;
220cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        boolean mRetaining;
221cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        boolean mRetainingStarted;
2229c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn        boolean mReportNextStart;
223cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        boolean mDestroyed;
224cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        boolean mListenerRegistered;
225cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
226cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        LoaderInfo mPendingLoader;
227cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
228cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callbacks) {
229cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mId = id;
230cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mArgs = args;
231cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mCallbacks = callbacks;
232cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
233cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
234cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        void start() {
235cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mRetaining && mRetainingStarted) {
236cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // Our owner is started, but we were being retained from a
237cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // previous instance in the started state...  so there is really
238cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // nothing to do here, since the loaders are still started.
239cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mStarted = true;
240cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                return;
241cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
242cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
243cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mStarted) {
244cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // If loader already started, don't restart.
245cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                return;
246cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
247cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
248cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mStarted = true;
249cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
250cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, "  Starting: " + this);
251cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mLoader == null && mCallbacks != null) {
252cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn               mLoader = mCallbacks.onCreateLoader(mId, mArgs);
253cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
254cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mLoader != null) {
255cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (mLoader.getClass().isMemberClass()
256cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        && !Modifier.isStatic(mLoader.getClass().getModifiers())) {
257cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    throw new IllegalArgumentException(
258cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                            "Object returned from onCreateLoader must not be a non-static inner member class: "
259cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                            + mLoader);
260cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
261cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (!mListenerRegistered) {
262cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mLoader.registerListener(mId, this);
263cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mListenerRegistered = true;
264cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
265cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mLoader.startLoading();
266cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
267cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
268cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
269cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        void retain() {
270cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, "  Retaining: " + this);
271cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mRetaining = true;
272cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mRetainingStarted = mStarted;
273cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mStarted = false;
274cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mCallbacks = null;
275cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
276cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
277cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        void finishRetain() {
278cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mRetaining) {
279cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (DEBUG) Log.v(TAG, "  Finished Retaining: " + this);
280cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mRetaining = false;
281cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (mStarted != mRetainingStarted) {
282cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    if (!mStarted) {
283cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        // This loader was retained in a started state, but
284cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        // at the end of retaining everything our owner is
285cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        // no longer started...  so make it stop.
286cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        stop();
287cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    }
288cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
289cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
290cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
2919c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn            if (mStarted && mHaveData && !mReportNextStart) {
292cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // This loader has retained its data, either completely across
293cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // a configuration change or just whatever the last data set
294cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // was after being restarted from a stop, and now at the point of
295cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // finishing the retain we find we remain started, have
296cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // our data, and the owner has a new callback...  so
297cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // let's deliver the data now.
298cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                callOnLoadFinished(mLoader, mData);
299cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
300cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
301cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
3029c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn        void reportStart() {
3039c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn            if (mStarted) {
3049c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn                if (mReportNextStart) {
3059c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn                    mReportNextStart = false;
3069c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn                    if (mHaveData) {
3079c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn                        callOnLoadFinished(mLoader, mData);
3089c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn                    }
3099c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn                }
3109c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn            }
3119c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn        }
3129c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn
313cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        void stop() {
314cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, "  Stopping: " + this);
315cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mStarted = false;
316cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (!mRetaining) {
317cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (mLoader != null && mListenerRegistered) {
318cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    // Let the loader know we're done with it
319cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mListenerRegistered = false;
320cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mLoader.unregisterListener(this);
321cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mLoader.stopLoading();
322cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
323cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
324cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
325cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
326cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        void destroy() {
327cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, "  Destroying: " + this);
328cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mDestroyed = true;
329cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            boolean needReset = mDeliveredData;
330cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mDeliveredData = false;
331cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mCallbacks != null && mLoader != null && mHaveData && needReset) {
332cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (DEBUG) Log.v(TAG, "  Reseting: " + this);
333cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                String lastBecause = null;
334cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (mActivity != null) {
335cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    lastBecause = mActivity.mFragments.mNoTransactionsBecause;
336cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mActivity.mFragments.mNoTransactionsBecause = "onLoaderReset";
337cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
338cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                try {
339cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mCallbacks.onLoaderReset(mLoader);
340cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                } finally {
341cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    if (mActivity != null) {
342cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        mActivity.mFragments.mNoTransactionsBecause = lastBecause;
343cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    }
344cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
345cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
346cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mCallbacks = null;
347cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mData = null;
348cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mHaveData = false;
349cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mLoader != null) {
350cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (mListenerRegistered) {
351cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mListenerRegistered = false;
352cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mLoader.unregisterListener(this);
353cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
354cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mLoader.reset();
355cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
356cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mPendingLoader != null) {
357cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mPendingLoader.destroy();
358cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
359cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
360cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
361cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        @Override public void onLoadComplete(Loader<Object> loader, Object data) {
362cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
363cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
364cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mDestroyed) {
365cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (DEBUG) Log.v(TAG, "  Ignoring load complete -- destroyed");
366cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                return;
367cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
368cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
369cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mLoaders.get(mId) != this) {
370cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // This data is not coming from the current active loader.
371cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // We don't care about it.
372cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (DEBUG) Log.v(TAG, "  Ignoring load complete -- not active");
373cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                return;
374cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
375cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
376cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            LoaderInfo pending = mPendingLoader;
377cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (pending != null) {
378cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // There is a new request pending and we were just
379cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // waiting for the old one to complete before starting
380cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // it.  So now it is time, switch over to the new loader.
381cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (DEBUG) Log.v(TAG, "  Switching to pending loader: " + pending);
382cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mPendingLoader = null;
383cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mLoaders.put(mId, null);
384cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                destroy();
385cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                installLoader(pending);
386cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                return;
387cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
388cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
389cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // Notify of the new data so the app can switch out the old data before
390cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // we try to destroy it.
391cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mData != data || !mHaveData) {
392cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mData = data;
393cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mHaveData = true;
394cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (mStarted) {
395cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    callOnLoadFinished(loader, data);
396cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
397cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
398cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
399cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            //if (DEBUG) Log.v(TAG, "  onLoadFinished returned: " + this);
400cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
401cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // We have now given the application the new loader with its
402cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // loaded data, so it should have stopped using the previous
403cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // loader.  If there is a previous loader on the inactive list,
404cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // clean it up.
405cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            LoaderInfo info = mInactiveLoaders.get(mId);
406cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (info != null && info != this) {
407cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                info.mDeliveredData = false;
408cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                info.destroy();
409cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mInactiveLoaders.remove(mId);
410cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
411abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell
4121199ae7067cdf8cf3eb30c057a61ae71a0aea1e5Adam Powell            if (mActivity != null && !hasRunningLoaders()) {
413abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                mActivity.mFragments.startPendingDeferredFragments();
414abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell            }
415cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
416cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
417cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        void callOnLoadFinished(Loader<Object> loader, Object data) {
418cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mCallbacks != null) {
419cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                String lastBecause = null;
420cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (mActivity != null) {
421cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    lastBecause = mActivity.mFragments.mNoTransactionsBecause;
422cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mActivity.mFragments.mNoTransactionsBecause = "onLoadFinished";
423cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
424cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                try {
425cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    if (DEBUG) Log.v(TAG, "  onLoadFinished in " + loader + ": "
426cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                            + loader.dataToString(data));
427cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mCallbacks.onLoadFinished(loader, data);
428cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                } finally {
429cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    if (mActivity != null) {
430cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        mActivity.mFragments.mNoTransactionsBecause = lastBecause;
431cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    }
432cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
433cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mDeliveredData = true;
434cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
435cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
436cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
437cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        @Override
438cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        public String toString() {
439cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            StringBuilder sb = new StringBuilder(64);
440cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            sb.append("LoaderInfo{");
441cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            sb.append(Integer.toHexString(System.identityHashCode(this)));
442cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            sb.append(" #");
443cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            sb.append(mId);
444cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            sb.append(" : ");
445cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            DebugUtils.buildShortClassTag(mLoader, sb);
446cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            sb.append("}}");
447cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            return sb.toString();
448cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
449cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
450cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
451cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            writer.print(prefix); writer.print("mId="); writer.print(mId);
452cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    writer.print(" mArgs="); writer.println(mArgs);
453cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            writer.print(prefix); writer.print("mCallbacks="); writer.println(mCallbacks);
454cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            writer.print(prefix); writer.print("mLoader="); writer.println(mLoader);
455cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mLoader != null) {
456cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mLoader.dump(prefix + "  ", fd, writer, args);
457cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
458cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mHaveData || mDeliveredData) {
459cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                writer.print(prefix); writer.print("mHaveData="); writer.print(mHaveData);
460cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        writer.print("  mDeliveredData="); writer.println(mDeliveredData);
461cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                writer.print(prefix); writer.print("mData="); writer.println(mData);
462cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
463cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            writer.print(prefix); writer.print("mStarted="); writer.print(mStarted);
4649c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn                    writer.print(" mReportNextStart="); writer.print(mReportNextStart);
465cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    writer.print(" mDestroyed="); writer.println(mDestroyed);
4669c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn            writer.print(prefix); writer.print("mRetaining="); writer.print(mRetaining);
4679c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn                    writer.print(" mRetainingStarted="); writer.print(mRetainingStarted);
4689c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn                    writer.print(" mListenerRegistered="); writer.println(mListenerRegistered);
469cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mPendingLoader != null) {
470cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                writer.print(prefix); writer.println("Pending Loader ");
471cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        writer.print(mPendingLoader); writer.println(":");
472cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mPendingLoader.dump(prefix + "  ", fd, writer, args);
473cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
474cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
475cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
476cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
4770adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn    LoaderManagerImpl(String who, FragmentActivity activity, boolean started) {
4780adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn        mWho = who;
479cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mActivity = activity;
480cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mStarted = started;
481cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
482cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
483cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    void updateActivity(FragmentActivity activity) {
484cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mActivity = activity;
485cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
486cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
487cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    private LoaderInfo createLoader(int id, Bundle args,
488cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            LoaderManager.LoaderCallbacks<Object> callback) {
489cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        LoaderInfo info = new LoaderInfo(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
490cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        Loader<Object> loader = callback.onCreateLoader(id, args);
491cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        info.mLoader = (Loader<Object>)loader;
492cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return info;
493cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
494cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
495cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    private LoaderInfo createAndInstallLoader(int id, Bundle args,
496cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            LoaderManager.LoaderCallbacks<Object> callback) {
497cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        try {
498cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mCreatingLoader = true;
499cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            LoaderInfo info = createLoader(id, args, callback);
500cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            installLoader(info);
501cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            return info;
502cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        } finally {
503cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mCreatingLoader = false;
504cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
505cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
506cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
507cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    void installLoader(LoaderInfo info) {
508cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mLoaders.put(info.mId, info);
509cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mStarted) {
510cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // The activity will start all existing loaders in it's onStart(),
511cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // so only start them here if we're past that point of the activitiy's
512cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // life cycle
513cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            info.start();
514cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
515cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
516cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
517cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
518cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Call to initialize a particular ID with a Loader.  If this ID already
519cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * has a Loader associated with it, it is left unchanged and any previous
520cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * callbacks replaced with the newly provided ones.  If there is not currently
521cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * a Loader for the ID, a new one is created and started.
522cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
523cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>This function should generally be used when a component is initializing,
524cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * to ensure that a Loader it relies on is created.  This allows it to re-use
525cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * an existing Loader's data if there already is one, so that for example
526cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * when an {@link Activity} is re-created after a configuration change it
527cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * does not need to re-create its loaders.
528cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
529cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>Note that in the case where an existing Loader is re-used, the
530cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <var>args</var> given here <em>will be ignored</em> because you will
531cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * continue using the previous Loader.
532cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
533cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param id A unique (to this LoaderManager instance) identifier under
534cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * which to manage the new Loader.
535cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param args Optional arguments that will be propagated to
536cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * {@link LoaderCallbacks#onCreateLoader(int, Bundle) LoaderCallbacks.onCreateLoader()}.
537cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param callback Interface implementing management of this Loader.  Required.
538cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Its onCreateLoader() method will be called while inside of the function to
539cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * instantiate the Loader object.
540cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
541cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    @SuppressWarnings("unchecked")
542cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
543cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mCreatingLoader) {
544cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            throw new IllegalStateException("Called while creating a loader");
545cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
546cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
547cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        LoaderInfo info = mLoaders.get(id);
548cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
549cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
550cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
551cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (info == null) {
552cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // Loader doesn't already exist; create.
553cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
554cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, "  Created new loader " + info);
555cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        } else {
556cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);
557cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
558cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
559cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
560cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (info.mHaveData && mStarted) {
561cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // If the loader has already generated its data, report it now.
562cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            info.callOnLoadFinished(info.mLoader, info.mData);
563cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
564cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
565cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return (Loader<D>)info.mLoader;
566cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
567cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
568cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
569cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Call to re-create the Loader associated with a particular ID.  If there
570cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * is currently a Loader associated with this ID, it will be
571cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * canceled/stopped/destroyed as appropriate.  A new Loader with the given
572cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * arguments will be created and its data delivered to you once available.
573cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
574cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>This function does some throttling of Loaders.  If too many Loaders
575cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * have been created for the given ID but not yet generated their data,
576cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * new calls to this function will create and return a new Loader but not
577cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * actually start it until some previous loaders have completed.
578cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
579cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>After calling this function, any previous Loaders associated with
580cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * this ID will be considered invalid, and you will receive no further
581cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * data updates from them.
582cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
583cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param id A unique (to this LoaderManager instance) identifier under
584cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * which to manage the new Loader.
585cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param args Optional arguments that will be propagated to
586cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * {@link LoaderCallbacks#onCreateLoader(int, Bundle) LoaderCallbacks.onCreateLoader()}.
587cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param callback Interface implementing management of this Loader.  Required.
588cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Its onCreateLoader() method will be called while inside of the function to
589cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * instantiate the Loader object.
590cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
591cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    @SuppressWarnings("unchecked")
592cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public <D> Loader<D> restartLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
593cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mCreatingLoader) {
594cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            throw new IllegalStateException("Called while creating a loader");
595cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
596cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
597cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        LoaderInfo info = mLoaders.get(id);
598cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args);
599cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (info != null) {
600cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            LoaderInfo inactive = mInactiveLoaders.get(id);
601cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (inactive != null) {
602cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (info.mHaveData) {
603cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    // This loader now has data...  we are probably being
604cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    // called from within onLoadComplete, where we haven't
605cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    // yet destroyed the last inactive loader.  So just do
606cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    // that now.
607cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    if (DEBUG) Log.v(TAG, "  Removing last inactive loader: " + info);
608cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    inactive.mDeliveredData = false;
609cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    inactive.destroy();
610cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    info.mLoader.abandon();
611cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mInactiveLoaders.put(id, info);
612cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                } else {
613cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    // We already have an inactive loader for this ID that we are
614cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    // waiting for!  What to do, what to do...
615cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    if (!info.mStarted) {
616cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        // The current Loader has not been started...  we thus
617cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        // have no reason to keep it around, so bam, slam,
618cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        // thank-you-ma'am.
619cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        if (DEBUG) Log.v(TAG, "  Current loader is stopped; replacing");
620cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        mLoaders.put(id, null);
621cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        info.destroy();
622cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    } else {
623cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        // Now we have three active loaders... we'll queue
624cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        // up this request to be processed once one of the other loaders
625cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        // finishes.
626cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        if (info.mPendingLoader != null) {
627cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                            if (DEBUG) Log.v(TAG, "  Removing pending loader: " + info.mPendingLoader);
628cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                            info.mPendingLoader.destroy();
629cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                            info.mPendingLoader = null;
630cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        }
631cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        if (DEBUG) Log.v(TAG, "  Enqueuing as new pending loader");
632cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        info.mPendingLoader = createLoader(id, args,
633cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                                (LoaderManager.LoaderCallbacks<Object>)callback);
634cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        return (Loader<D>)info.mPendingLoader.mLoader;
635cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    }
636cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
637cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            } else {
638cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // Keep track of the previous instance of this loader so we can destroy
639cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // it when the new one completes.
640cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (DEBUG) Log.v(TAG, "  Making last loader inactive: " + info);
641cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                info.mLoader.abandon();
642cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mInactiveLoaders.put(id, info);
643cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
644cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
645cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
646cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
647cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return (Loader<D>)info.mLoader;
648cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
649cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
650cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
651cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Rip down, tear apart, shred to pieces a current Loader ID.  After returning
652cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * from this function, any Loader objects associated with this ID are
653cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * destroyed.  Any data associated with them is destroyed.  You better not
654cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * be using it when you do this.
655cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param id Identifier of the Loader to be destroyed.
656cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
657cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void destroyLoader(int id) {
658cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mCreatingLoader) {
659cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            throw new IllegalStateException("Called while creating a loader");
660cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
661cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
662cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id);
663cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        int idx = mLoaders.indexOfKey(id);
664cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (idx >= 0) {
665cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            LoaderInfo info = mLoaders.valueAt(idx);
666cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mLoaders.removeAt(idx);
667cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            info.destroy();
668cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
669cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        idx = mInactiveLoaders.indexOfKey(id);
670cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (idx >= 0) {
671cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            LoaderInfo info = mInactiveLoaders.valueAt(idx);
672cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mInactiveLoaders.removeAt(idx);
673cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            info.destroy();
674cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
6751199ae7067cdf8cf3eb30c057a61ae71a0aea1e5Adam Powell        if (mActivity != null && !hasRunningLoaders()) {
6761199ae7067cdf8cf3eb30c057a61ae71a0aea1e5Adam Powell            mActivity.mFragments.startPendingDeferredFragments();
6771199ae7067cdf8cf3eb30c057a61ae71a0aea1e5Adam Powell        }
678cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
679cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
680cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
681cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Return the most recent Loader object associated with the
682cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * given ID.
683cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
684cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    @SuppressWarnings("unchecked")
685cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public <D> Loader<D> getLoader(int id) {
686cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mCreatingLoader) {
687cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            throw new IllegalStateException("Called while creating a loader");
688cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
689cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
690cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        LoaderInfo loaderInfo = mLoaders.get(id);
691cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (loaderInfo != null) {
692cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (loaderInfo.mPendingLoader != null) {
693cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                return (Loader<D>)loaderInfo.mPendingLoader.mLoader;
694cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
695cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            return (Loader<D>)loaderInfo.mLoader;
696cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
697cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return null;
698cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
699cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
700cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    void doStart() {
701cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (DEBUG) Log.v(TAG, "Starting in " + this);
702cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mStarted) {
703cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            RuntimeException e = new RuntimeException("here");
704cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            e.fillInStackTrace();
705cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            Log.w(TAG, "Called doStart when already started: " + this, e);
706cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            return;
707cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
708cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
709cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mStarted = true;
710cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
711cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        // Call out to sub classes so they can start their loaders
712cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        // Let the existing loaders know that we want to be notified when a load is complete
713cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        for (int i = mLoaders.size()-1; i >= 0; i--) {
714cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mLoaders.valueAt(i).start();
715cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
716cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
717cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
718cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    void doStop() {
719cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (DEBUG) Log.v(TAG, "Stopping in " + this);
720cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (!mStarted) {
721cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            RuntimeException e = new RuntimeException("here");
722cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            e.fillInStackTrace();
723cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            Log.w(TAG, "Called doStop when not started: " + this, e);
724cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            return;
725cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
726cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
727cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        for (int i = mLoaders.size()-1; i >= 0; i--) {
728cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mLoaders.valueAt(i).stop();
729cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
730cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mStarted = false;
731cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
732cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
733cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    void doRetain() {
734cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (DEBUG) Log.v(TAG, "Retaining in " + this);
735cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (!mStarted) {
736cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            RuntimeException e = new RuntimeException("here");
737cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            e.fillInStackTrace();
738cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            Log.w(TAG, "Called doRetain when not started: " + this, e);
739cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            return;
740cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
741cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
742cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mRetaining = true;
743cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mStarted = false;
744cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        for (int i = mLoaders.size()-1; i >= 0; i--) {
745cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mLoaders.valueAt(i).retain();
746cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
747cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
748cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
749cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    void finishRetain() {
750cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mRetaining) {
751cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, "Finished Retaining in " + this);
752cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
753cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mRetaining = false;
754cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            for (int i = mLoaders.size()-1; i >= 0; i--) {
755cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mLoaders.valueAt(i).finishRetain();
756cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
757cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
758cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
759cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
7609c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn    void doReportNextStart() {
7619c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn        for (int i = mLoaders.size()-1; i >= 0; i--) {
7629c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn            mLoaders.valueAt(i).mReportNextStart = true;
7639c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn        }
7649c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn    }
7659c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn
7669c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn    void doReportStart() {
7679c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn        for (int i = mLoaders.size()-1; i >= 0; i--) {
7689c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn            mLoaders.valueAt(i).reportStart();
7699c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn        }
7709c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn    }
7719c53b844bd525e6a04e17291efc38713893074cdDianne Hackborn
772cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    void doDestroy() {
773cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (!mRetaining) {
774cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, "Destroying Active in " + this);
775cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            for (int i = mLoaders.size()-1; i >= 0; i--) {
776cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mLoaders.valueAt(i).destroy();
777cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
778cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
779cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
780cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this);
781cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
782cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mInactiveLoaders.valueAt(i).destroy();
783cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
784cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mInactiveLoaders.clear();
785cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
786cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
787cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    @Override
788cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public String toString() {
789cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        StringBuilder sb = new StringBuilder(128);
790cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        sb.append("LoaderManager{");
791cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        sb.append(Integer.toHexString(System.identityHashCode(this)));
792cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        sb.append(" in ");
793cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        DebugUtils.buildShortClassTag(mActivity, sb);
794cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        sb.append("}}");
795cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return sb.toString();
796cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
797cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
798cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    @Override
799cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
800cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mLoaders.size() > 0) {
801cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            writer.print(prefix); writer.println("Active Loaders:");
802cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            String innerPrefix = prefix + "    ";
803cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            for (int i=0; i < mLoaders.size(); i++) {
804cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                LoaderInfo li = mLoaders.valueAt(i);
805cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                writer.print(prefix); writer.print("  #"); writer.print(mLoaders.keyAt(i));
806cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        writer.print(": "); writer.println(li.toString());
807cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                li.dump(innerPrefix, fd, writer, args);
808cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
809cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
810cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mInactiveLoaders.size() > 0) {
811cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            writer.print(prefix); writer.println("Inactive Loaders:");
812cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            String innerPrefix = prefix + "    ";
813cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            for (int i=0; i < mInactiveLoaders.size(); i++) {
814cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                LoaderInfo li = mInactiveLoaders.valueAt(i);
815cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                writer.print(prefix); writer.print("  #"); writer.print(mInactiveLoaders.keyAt(i));
816cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        writer.print(": "); writer.println(li.toString());
817cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                li.dump(innerPrefix, fd, writer, args);
818cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
819cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
820cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
821abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell
822abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell    @Override
823abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell    public boolean hasRunningLoaders() {
824abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell        boolean loadersRunning = false;
825abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell        final int count = mLoaders.size();
826abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell        for (int i = 0; i < count; i++) {
827abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell            final LoaderInfo li = mLoaders.valueAt(i);
828abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell            loadersRunning |= li.mStarted && !li.mDeliveredData;
829abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell        }
830abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell        return loadersRunning;
831abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell    }
832cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn}
833