19911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton/*
29911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * Copyright (C) 2010 The Android Open Source Project
39911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton *
49911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License");
59911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * you may not use this file except in compliance with the License.
69911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * You may obtain a copy of the License at
79911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton *
89911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton *      http://www.apache.org/licenses/LICENSE-2.0
99911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton *
109911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * Unless required by applicable law or agreed to in writing, software
119911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS,
129911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * See the License for the specific language governing permissions and
149911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * limitations under the License.
159911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton */
169911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
179911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamiltonpackage android.content;
189911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
199911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamiltonimport android.os.AsyncTask;
20247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackbornimport android.os.Handler;
21a7771df3696954f0e279407e8894a916a7cb26ccJeff Brownimport android.os.OperationCanceledException;
22247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackbornimport android.os.SystemClock;
23c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brownimport android.util.Log;
24247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackbornimport android.util.TimeUtils;
25cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov
26247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackbornimport java.io.FileDescriptor;
27247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackbornimport java.io.PrintWriter;
2859d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikovimport java.util.concurrent.CountDownLatch;
29d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkeyimport java.util.concurrent.Executor;
309911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
319911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton/**
329567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * Abstract Loader that provides an {@link AsyncTask} to do the work.  See
339567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * {@link Loader} and {@link android.app.LoaderManager} for more details.
349567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn *
359567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * <p>Here is an example implementation of an AsyncTaskLoader subclass that
369567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * loads the currently installed applications from the package manager.  This
379567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * implementation takes care of retrieving the application labels and sorting
389567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * its result set from them, monitoring for changes to the installed
399567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * applications, and rebuilding the list when a change in configuration requires
409567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * this (such as a locale change).
419567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn *
429567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LoaderCustom.java
439567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn *      loader}
449567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn *
459567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * <p>An example implementation of a fragment that uses the above loader to show
469567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * the currently installed applications in a list is below.
479567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn *
489567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LoaderCustom.java
499567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn *      fragment}
50bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov *
519911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * @param <D> the data type to be loaded.
529911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton */
539911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamiltonpublic abstract class AsyncTaskLoader<D> extends Loader<D> {
54540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn    static final String TAG = "AsyncTaskLoader";
55540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn    static final boolean DEBUG = false;
56cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov
57247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
58b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        private final CountDownLatch mDone = new CountDownLatch(1);
59bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov
60b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        // Set to true to indicate that the task has been posted to a handler for
61b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        // execution at a later time.  Used to throttle updates.
62247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        boolean waiting;
63bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov
649911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        /* Runs on a worker thread */
659911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        @Override
669911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        protected D doInBackground(Void... params) {
67c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown            if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
68b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            try {
69b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                D data = AsyncTaskLoader.this.onLoadInBackground();
70c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown                if (DEBUG) Log.v(TAG, this + "  <<< doInBackground");
71b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                return data;
72b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            } catch (OperationCanceledException ex) {
73b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                if (!isCancelled()) {
74b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    // onLoadInBackground threw a canceled exception spuriously.
75b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    // This is problematic because it means that the LoaderManager did not
76b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    // cancel the Loader itself and still expects to receive a result.
77b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    // Additionally, the Loader's own state will not have been updated to
78b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    // reflect the fact that the task was being canceled.
79b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    // So we treat this case as an unhandled exception.
80b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    throw ex;
81b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                }
82c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown                if (DEBUG) Log.v(TAG, this + "  <<< doInBackground (was canceled)", ex);
83b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                return null;
84b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            }
859911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        }
869911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
879911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        /* Runs on the UI thread */
889911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        @Override
899911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        protected void onPostExecute(D data) {
90c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown            if (DEBUG) Log.v(TAG, this + " onPostExecute");
9159d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov            try {
9259d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov                AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
9359d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov            } finally {
94b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                mDone.countDown();
9559d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov            }
969911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        }
97bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov
98b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        /* Runs on the UI thread */
99bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov        @Override
100b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        protected void onCancelled(D data) {
101c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown            if (DEBUG) Log.v(TAG, this + " onCancelled");
10259d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov            try {
103b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                AsyncTaskLoader.this.dispatchOnCancelled(this, data);
10459d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov            } finally {
105b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                mDone.countDown();
10659d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov            }
107247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
108247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
109b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        /* Runs on the UI thread, when the waiting task is posted to a handler.
110b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown         * This method is only executed when task execution was deferred (waiting was true). */
111247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        @Override
112247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        public void run() {
113247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            waiting = false;
114247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            AsyncTaskLoader.this.executePendingTask();
115bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov        }
116b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown
117b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        /* Used for testing purposes to wait for the task to complete. */
118b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        public void waitForLoader() {
119b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            try {
120b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                mDone.await();
121b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            } catch (InterruptedException e) {
122b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                // Ignore
123b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            }
124b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        }
1259911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    }
1269911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
127d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    private final Executor mExecutor;
128d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey
129cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov    volatile LoadTask mTask;
130247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    volatile LoadTask mCancellingTask;
131247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
132247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    long mUpdateThrottle;
133247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    long mLastLoadCompleteTime = -10000;
134247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    Handler mHandler;
1359911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
1369911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    public AsyncTaskLoader(Context context) {
137d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey        this(context, AsyncTask.THREAD_POOL_EXECUTOR);
138d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    }
139d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey
140d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    /** {@hide} */
141d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    public AsyncTaskLoader(Context context, Executor executor) {
1429911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        super(context);
143d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey        mExecutor = executor;
1449911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    }
1459911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
146247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    /**
147247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     * Set amount to throttle updates by.  This is the minimum time from
148b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * when the last {@link #loadInBackground()} call has completed until
149247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     * a new load is scheduled.
150247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     *
151247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     * @param delayMS Amount of delay, in milliseconds.
152247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     */
153247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    public void setUpdateThrottle(long delayMS) {
154247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        mUpdateThrottle = delayMS;
155247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        if (delayMS != 0) {
156247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            mHandler = new Handler();
157247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
158247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    }
159247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
1609911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    @Override
161a2ea747faaf5fcd437afbaaf4085cfc29e7c16b8Dianne Hackborn    protected void onForceLoad() {
1620e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn        super.onForceLoad();
163bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov        cancelLoad();
1649911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        mTask = new LoadTask();
165c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown        if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
166247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        executePendingTask();
1679911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    }
1689911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
169b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown    @Override
170b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown    protected boolean onCancelLoad() {
171c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown        if (DEBUG) Log.v(TAG, "onCancelLoad: mTask=" + mTask);
1729911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        if (mTask != null) {
173247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            if (mCancellingTask != null) {
174247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                // There was a pending task already waiting for a previous
175247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                // one being canceled; just drop it.
176c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown                if (DEBUG) Log.v(TAG,
177540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn                        "cancelLoad: still waiting for cancelled task; dropping next");
178247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                if (mTask.waiting) {
179247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    mTask.waiting = false;
180247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    mHandler.removeCallbacks(mTask);
181247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                }
182247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mTask = null;
183247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                return false;
184247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            } else if (mTask.waiting) {
185247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                // There is a task, but it is waiting for the time it should
186247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                // execute.  We can just toss it.
187c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown                if (DEBUG) Log.v(TAG, "cancelLoad: task is waiting, dropping it");
188247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mTask.waiting = false;
189247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mHandler.removeCallbacks(mTask);
190247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mTask = null;
191247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                return false;
192247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            } else {
193247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                boolean cancelled = mTask.cancel(false);
194c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown                if (DEBUG) Log.v(TAG, "cancelLoad: cancelled=" + cancelled);
195247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                if (cancelled) {
196247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    mCancellingTask = mTask;
197b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    cancelLoadInBackground();
198247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                }
199247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mTask = null;
200247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                return cancelled;
201247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            }
2029911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        }
2039911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        return false;
2049911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    }
205bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov
206bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov    /**
207bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov     * Called if the task was canceled before it was completed.  Gives the class a chance
208b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * to clean up post-cancellation and to properly dispose of the result.
209b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
210b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @param data The value that was returned by {@link #loadInBackground}, or null
211b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * if the task threw {@link OperationCanceledException}.
212bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov     */
213327fbd2c8fa294b919475feb4c74a74ee1981e02Dianne Hackborn    public void onCanceled(D data) {
214327fbd2c8fa294b919475feb4c74a74ee1981e02Dianne Hackborn    }
2154afde4fda383116a9730aea1e931d4bce7ea0fd0Dmitri Plotnikov
216247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    void executePendingTask() {
217247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        if (mCancellingTask == null && mTask != null) {
218247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            if (mTask.waiting) {
219247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mTask.waiting = false;
220247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mHandler.removeCallbacks(mTask);
221247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            }
222247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            if (mUpdateThrottle > 0) {
223247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                long now = SystemClock.uptimeMillis();
224247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                if (now < (mLastLoadCompleteTime+mUpdateThrottle)) {
225247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    // Not yet time to do another load.
226c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown                    if (DEBUG) Log.v(TAG, "Waiting until "
227540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn                            + (mLastLoadCompleteTime+mUpdateThrottle)
228540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn                            + " to execute: " + mTask);
229247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    mTask.waiting = true;
230247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle);
231247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    return;
232247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                }
233247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            }
234c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown            if (DEBUG) Log.v(TAG, "Executing: " + mTask);
235d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey            mTask.executeOnExecutor(mExecutor, (Void[]) null);
236247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
237247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    }
238247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
239247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    void dispatchOnCancelled(LoadTask task, D data) {
240327fbd2c8fa294b919475feb4c74a74ee1981e02Dianne Hackborn        onCanceled(data);
241247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        if (mCancellingTask == task) {
242c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown            if (DEBUG) Log.v(TAG, "Cancelled task is now canceled!");
243ca614f78bed7eebf9dbfd77ba5720a0b5eeed816Dianne Hackborn            rollbackContentChanged();
244247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            mLastLoadCompleteTime = SystemClock.uptimeMillis();
245247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            mCancellingTask = null;
246c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown            if (DEBUG) Log.v(TAG, "Delivering cancellation");
247b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            deliverCancellation();
248247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            executePendingTask();
249247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
250247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    }
251247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
2520e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn    void dispatchOnLoadComplete(LoadTask task, D data) {
2530e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn        if (mTask != task) {
254c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown            if (DEBUG) Log.v(TAG, "Load complete of old task, trying to cancel");
255247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            dispatchOnCancelled(task, data);
2560e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn        } else {
257260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn            if (isAbandoned()) {
258260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn                // This cursor has been abandoned; just cancel the new data.
259260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn                onCanceled(data);
260260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn            } else {
261ca614f78bed7eebf9dbfd77ba5720a0b5eeed816Dianne Hackborn                commitContentChanged();
262260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn                mLastLoadCompleteTime = SystemClock.uptimeMillis();
263260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn                mTask = null;
264c64ff3782c71ce7b5a92b7d91199a922ea0a37d9Jeff Brown                if (DEBUG) Log.v(TAG, "Delivering result");
265260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn                deliverResult(data);
266260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn            }
2670e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn        }
2689911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    }
2699911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
2709911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    /**
271b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Called on a worker thread to perform the actual load and to return
272b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * the result of the load operation.
273b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
274b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Implementations should not deliver the result directly, but should return them
275b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * from this method, which will eventually end up calling {@link #deliverResult} on
276b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * the UI thread.  If implementations need to process the results on the UI thread
277b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * they may override {@link #deliverResult} and do so there.
278b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
279b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * To support cancellation, this method should periodically check the value of
280b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * {@link #isLoadInBackgroundCanceled} and terminate when it returns true.
281b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Subclasses may also override {@link #cancelLoadInBackground} to interrupt the load
282b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * directly instead of polling {@link #isLoadInBackgroundCanceled}.
283b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
284b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * When the load is canceled, this method may either return normally or throw
285b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * {@link OperationCanceledException}.  In either case, the {@link Loader} will
286b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
287b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * result object, if any.
288b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
289b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @return The result of the load operation.
290b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
291b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @throws OperationCanceledException if the load is canceled during execution.
292b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
293b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @see #isLoadInBackgroundCanceled
294b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @see #cancelLoadInBackground
295b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @see #onCanceled
296247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     */
297247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    public abstract D loadInBackground();
298247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
299247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    /**
300b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Calls {@link #loadInBackground()}.
301b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
302b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * This method is reserved for use by the loader framework.
303b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Subclasses should override {@link #loadInBackground} instead of this method.
304b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
305b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @return The result of the load operation.
3069911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton     *
307b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @throws OperationCanceledException if the load is canceled during execution.
308b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
309b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @see #loadInBackground
3109911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton     */
311247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    protected D onLoadInBackground() {
312247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        return loadInBackground();
313247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    }
314cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov
315cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov    /**
316b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Called on the main thread to abort a load in progress.
317b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
318b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Override this method to abort the current invocation of {@link #loadInBackground}
319b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * that is running in the background on a worker thread.
32075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
321b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * This method should do nothing if {@link #loadInBackground} has not started
322b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * running or if it has already finished.
323b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
324b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @see #loadInBackground
32575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
326b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown    public void cancelLoadInBackground() {
32775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
32875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
32975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
330b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Returns true if the current invocation of {@link #loadInBackground} is being canceled.
331b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
332b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @return True if the current invocation of {@link #loadInBackground} is being canceled.
33375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
334b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @see #loadInBackground
33575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
336b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown    public boolean isLoadInBackgroundCanceled() {
33775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        return mCancellingTask != null;
33875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
33975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
34075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
341cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov     * Locks the current thread until the loader completes the current load
342cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov     * operation. Returns immediately if there is no load operation running.
34359d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov     * Should not be called from the UI thread: calling it from the UI
34459d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov     * thread would cause a deadlock.
345cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov     * <p>
346247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     * Use for testing only.  <b>Never</b> call this from a UI thread.
3474afde4fda383116a9730aea1e931d4bce7ea0fd0Dmitri Plotnikov     *
3484afde4fda383116a9730aea1e931d4bce7ea0fd0Dmitri Plotnikov     * @hide
349cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov     */
350cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov    public void waitForLoader() {
351cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov        LoadTask task = mTask;
352cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov        if (task != null) {
353b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            task.waitForLoader();
354cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov        }
355cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov    }
356247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
357247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    @Override
358247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
359247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        super.dump(prefix, fd, writer, args);
360247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        if (mTask != null) {
361247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            writer.print(prefix); writer.print("mTask="); writer.print(mTask);
362247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    writer.print(" waiting="); writer.println(mTask.waiting);
363247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
364247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        if (mCancellingTask != null) {
365247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            writer.print(prefix); writer.print("mCancellingTask="); writer.print(mCancellingTask);
366247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    writer.print(" waiting="); writer.println(mCancellingTask.waiting);
367247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
368247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        if (mUpdateThrottle != 0) {
369247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            writer.print(prefix); writer.print("mUpdateThrottle=");
370247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    TimeUtils.formatDuration(mUpdateThrottle, writer);
371247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    writer.print(" mLastLoadCompleteTime=");
372247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    TimeUtils.formatDuration(mLastLoadCompleteTime,
373247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                            SystemClock.uptimeMillis(), writer);
374247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    writer.println();
375247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
376247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    }
3779911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton}
378