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.content;
18cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
19cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.content.Context;
20cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.database.ContentObserver;
21cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.os.Handler;
22cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.support.v4.util.DebugUtils;
23cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
24cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport java.io.FileDescriptor;
25cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport java.io.PrintWriter;
26cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
27cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn/**
28cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Static library support version of the framework's {@link android.content.Loader}.
29cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Used to write apps that run on platforms prior to Android 3.0.  When running
30cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * on Android 3.0 or above, this implementation is still used; it does not try
31cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * to switch to the framework's implementation.  See the framework SDK
32cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * documentation for a class overview.
33cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */
34cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornpublic class Loader<D> {
35cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    int mId;
36cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    OnLoadCompleteListener<D> mListener;
37cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    Context mContext;
38cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    boolean mStarted = false;
39cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    boolean mAbandoned = false;
40cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    boolean mReset = true;
41cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    boolean mContentChanged = false;
4280a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn    boolean mProcessingChange = false;
43cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
447dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn    /**
457dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * An implementation of a ContentObserver that takes care of connecting
467dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * it to the Loader to have the loader re-load its data when the observer
477dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * is told it has changed.  You do not normally need to use this yourself;
487dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * it is used for you by {@link android.support.v4.content.CursorLoader}
497dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * to take care of executing an update when the cursor's backing data changes.
507dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     */
51cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public final class ForceLoadContentObserver extends ContentObserver {
52cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        public ForceLoadContentObserver() {
53cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            super(new Handler());
54cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
55cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
56cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        @Override
57cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        public boolean deliverSelfNotifications() {
58cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            return true;
59cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
60cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
61cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        @Override
62cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        public void onChange(boolean selfChange) {
63cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            onContentChanged();
64cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
65cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
66cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
677dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn    /**
687dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * Interface that is implemented to discover when a Loader has finished
697dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * loading its data.  You do not normally need to implement this yourself;
707dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * it is used in the implementation of {@link android.support.v4.app.LoaderManager}
717dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * to find out when a Loader it is managing has completed so that this can
727dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * be reported to its client.  This interface should only be used if a
737dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * Loader is not being used in conjunction with LoaderManager.
747dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     */
75cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public interface OnLoadCompleteListener<D> {
76cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        /**
77cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * Called on the thread that created the Loader when the load is complete.
78cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         *
79cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * @param loader the loader that completed the load
80cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         * @param data the result of the load
81cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn         */
82cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        public void onLoadComplete(Loader<D> loader, D data);
83cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
84cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
85cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
86cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Stores away the application context associated with context. Since Loaders can be used
87cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * across multiple activities it's dangerous to store the context directly.
88cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
89cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param context used to retrieve the application context.
90cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
91cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public Loader(Context context) {
92cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mContext = context.getApplicationContext();
93cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
94cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
95cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
96cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Sends the result of the load to the registered listener. Should only be called by subclasses.
97cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
98cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Must be called from the process's main thread.
99cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
100cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param data the result of the load
101cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
102cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void deliverResult(D data) {
103cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mListener != null) {
104cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mListener.onLoadComplete(this, data);
105cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
106cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
107cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
108cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
109cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @return an application context retrieved from the Context passed to the constructor.
110cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
111cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public Context getContext() {
112cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return mContext;
113cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
114cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
115cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
116cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @return the ID of this loader
117cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
118cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public int getId() {
119cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return mId;
120cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
121cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
122cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
123cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Registers a class that will receive callbacks when a load is complete.
124cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * The callback will be called on the process's main thread so it's safe to
125cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * pass the results to widgets.
126cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
127cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>Must be called from the process's main thread.
128cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
129cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void registerListener(int id, OnLoadCompleteListener<D> listener) {
130cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mListener != null) {
131cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            throw new IllegalStateException("There is already a listener registered");
132cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
133cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mListener = listener;
134cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mId = id;
135cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
136cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
137cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
138cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Remove a listener that was previously added with {@link #registerListener}.
139cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
140cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Must be called from the process's main thread.
141cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
142cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void unregisterListener(OnLoadCompleteListener<D> listener) {
143cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mListener == null) {
144cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            throw new IllegalStateException("No listener register");
145cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
146cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mListener != listener) {
147cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            throw new IllegalArgumentException("Attempting to unregister the wrong listener");
148cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
149cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mListener = null;
150cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
151cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
152cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
153cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Return whether this load has been started.  That is, its {@link #startLoading()}
154cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * has been called and no calls to {@link #stopLoading()} or
155cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * {@link #reset()} have yet been made.
156cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
157cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public boolean isStarted() {
158cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return mStarted;
159cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
160cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
161cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
162cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Return whether this loader has been abandoned.  In this state, the
163cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * loader <em>must not</em> report any new data, and <em>must</em> keep
164cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * its last reported data valid until it is finally reset.
165cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
166cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public boolean isAbandoned() {
167cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return mAbandoned;
168cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
169cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
170cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
171cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Return whether this load has been reset.  That is, either the loader
172cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * has not yet been started for the first time, or its {@link #reset()}
173cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * has been called.
174cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
175cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public boolean isReset() {
176cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return mReset;
177cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
178cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
179cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
180cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Starts an asynchronous load of the Loader's data. When the result
181cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * is ready the callbacks will be called on the process's main thread.
182cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * If a previous load has been completed and is still valid
183cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * the result may be passed to the callbacks immediately.
184cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * The loader will monitor the source of
185cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * the data set and may deliver future callbacks if the source changes.
186cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Calling {@link #stopLoading} will stop the delivery of callbacks.
187cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
188cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>This updates the Loader's internal state so that
189cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * {@link #isStarted()} and {@link #isReset()} will return the correct
190cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * values, and then calls the implementation's {@link #onStartLoading()}.
191cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
192cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>Must be called from the process's main thread.
193cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
194cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public final void startLoading() {
195cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mStarted = true;
196cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mReset = false;
197cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mAbandoned = false;
198cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        onStartLoading();
199cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
200cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
201cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
202cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Subclasses must implement this to take care of loading their data,
203cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * as per {@link #startLoading()}.  This is not called by clients directly,
204cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * but as a result of a call to {@link #startLoading()}.
205cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
206cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    protected void onStartLoading() {
207cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
208cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
209cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
210cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
211cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * loaded data set and load a new one.  This simply calls through to the
212cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * implementation's {@link #onForceLoad()}.  You generally should only call this
213cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * when the loader is started -- that is, {@link #isStarted()} returns true.
214cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
215cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>Must be called from the process's main thread.
216cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
217cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void forceLoad() {
218cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        onForceLoad();
219cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
220cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
221cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
222cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Subclasses must implement this to take care of requests to {@link #forceLoad()}.
223cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * This will always be called from the process's main thread.
224cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
225cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    protected void onForceLoad() {
226cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
227cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
228cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
229cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Stops delivery of updates until the next time {@link #startLoading()} is called.
230cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Implementations should <em>not</em> invalidate their data at this point --
231cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * clients are still free to use the last data the loader reported.  They will,
232cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * however, typically stop reporting new data if the data changes; they can
233cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * still monitor for changes, but must not report them to the client until and
234cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * if {@link #startLoading()} is later called.
235cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
236cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>This updates the Loader's internal state so that
237cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * {@link #isStarted()} will return the correct
238cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * value, and then calls the implementation's {@link #onStopLoading()}.
239cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
240cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>Must be called from the process's main thread.
241cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
242cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void stopLoading() {
243cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mStarted = false;
244cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        onStopLoading();
245cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
246cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
247cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
248cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Subclasses must implement this to take care of stopping their loader,
249cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * as per {@link #stopLoading()}.  This is not called by clients directly,
250cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * but as a result of a call to {@link #stopLoading()}.
251cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * This will always be called from the process's main thread.
252cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
253cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    protected void onStopLoading() {
254cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
255cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
256cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
257cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Tell the Loader that it is being abandoned.  This is called prior
258cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * to {@link #reset} to have it retain its current data but not report
259cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * any new data.
260cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
261cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void abandon() {
262cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mAbandoned = true;
263cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        onAbandon();
264cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
265cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
266cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
267cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Subclasses implement this to take care of being abandoned.  This is
268cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * an optional intermediate state prior to {@link #onReset()} -- it means that
269cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * the client is no longer interested in any new data from the loader,
270cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * so the loader must not report any further updates.  However, the
271cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * loader <em>must</em> keep its last reported data valid until the final
272cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * {@link #onReset()} happens.  You can retrieve the current abandoned
273cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * state with {@link #isAbandoned}.
274cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
275cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    protected void onAbandon() {
276cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
277cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
278cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
279cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Resets the state of the Loader.  The Loader should at this point free
280cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * all of its resources, since it may never be called again; however, its
281cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * {@link #startLoading()} may later be called at which point it must be
282cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * able to start running again.
283cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
284cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>This updates the Loader's internal state so that
285cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * {@link #isStarted()} and {@link #isReset()} will return the correct
286cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * values, and then calls the implementation's {@link #onReset()}.
287cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
288cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>Must be called from the process's main thread.
289cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
290cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void reset() {
291cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        onReset();
292cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mReset = true;
293cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mStarted = false;
294cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mAbandoned = false;
295cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mContentChanged = false;
29680a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn        mProcessingChange = false;
297cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
298cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
299cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
300cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Subclasses must implement this to take care of resetting their loader,
301cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * as per {@link #reset()}.  This is not called by clients directly,
302cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * but as a result of a call to {@link #reset()}.
303cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * This will always be called from the process's main thread.
304cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
305cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    protected void onReset() {
306cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
307cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
308cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
309cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Take the current flag indicating whether the loader's content had
310cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * changed while it was stopped.  If it had, true is returned and the
311cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * flag is cleared.
312cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
313cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public boolean takeContentChanged() {
314cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        boolean res = mContentChanged;
315cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mContentChanged = false;
31680a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn        mProcessingChange |= res;
317cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return res;
318cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
31980a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn
32080a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn    /**
32180a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn     * Commit that you have actually fully processed a content change that
32280a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn     * was returned by {@link #takeContentChanged}.  This is for use with
32380a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn     * {@link #rollbackContentChanged()} to handle situations where a load
32480a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn     * is cancelled.  Call this when you have completely processed a load
32580a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn     * without it being cancelled.
32680a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn     */
32780a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn    public void commitContentChanged() {
32880a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn        mProcessingChange = false;
32980a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn    }
33080a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn
33180a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn    /**
33280a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn     * Report that you have abandoned the processing of a content change that
33380a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn     * was returned by {@link #takeContentChanged()} and would like to rollback
33480a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn     * to the state where there is again a pending content change.  This is
33580a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn     * to handle the case where a data load due to a content change has been
33680a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn     * canceled before its data was delivered back to the loader.
33780a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn     */
33880a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn    public void rollbackContentChanged() {
33980a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn        if (mProcessingChange) {
34080a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn            mContentChanged = true;
34180a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn        }
34280a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn    }
34380a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn
344cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
345cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Called when {@link ForceLoadContentObserver} detects a change.  The
346cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * default implementation checks to see if the loader is currently started;
347cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * if so, it simply calls {@link #forceLoad()}; otherwise, it sets a flag
348cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * so that {@link #takeContentChanged()} returns true.
349cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
350cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>Must be called from the process's main thread.
351cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
352cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void onContentChanged() {
353cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mStarted) {
354cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            forceLoad();
355cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        } else {
356cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // This loader has been stopped, so we don't want to load
357cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // new data right now...  but keep track of it changing to
358cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // refresh later if we start again.
359cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mContentChanged = true;
360cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
361cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
362cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
363cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
364cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * For debugging, converts an instance of the Loader's data class to
365cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * a string that can be printed.  Must handle a null data.
366cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
367cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public String dataToString(D data) {
368cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        StringBuilder sb = new StringBuilder(64);
369cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        DebugUtils.buildShortClassTag(data, sb);
370cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        sb.append("}");
371cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return sb.toString();
372cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
373cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
374cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    @Override
375cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public String toString() {
376cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        StringBuilder sb = new StringBuilder(64);
377cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        DebugUtils.buildShortClassTag(this, sb);
378cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        sb.append(" id=");
379cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        sb.append(mId);
380cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        sb.append("}");
381cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return sb.toString();
382cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
383cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
384cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
385cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Print the Loader's state into the given stream.
386cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
387cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param prefix Text to print at the front of each line.
388cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param fd The raw file descriptor that the dump is being sent to.
389cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param writer A PrintWriter to which the dump is to be set.
390cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param args Additional arguments to the dump request.
391cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
392cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
393cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        writer.print(prefix); writer.print("mId="); writer.print(mId);
394cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                writer.print(" mListener="); writer.println(mListener);
39580a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn        if (mStarted || mContentChanged || mProcessingChange) {
39680a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn            writer.print(prefix); writer.print("mStarted="); writer.print(mStarted);
39780a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn                    writer.print(" mContentChanged="); writer.print(mContentChanged);
39880a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn                    writer.print(" mProcessingChange="); writer.println(mProcessingChange);
39980a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn        }
40080a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn        if (mAbandoned || mReset) {
40180a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn            writer.print(prefix); writer.print("mAbandoned="); writer.print(mAbandoned);
40280a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn                    writer.print(" mReset="); writer.println(mReset);
40380a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn        }
404cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
405cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn}