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; 23540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackbornimport android.util.Slog; 24247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackbornimport android.util.TimeUtils; 25cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov 26247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackbornimport java.io.FileDescriptor; 27247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackbornimport java.io.PrintWriter; 2859d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikovimport java.util.concurrent.CountDownLatch; 299911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton 309911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton/** 319567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * Abstract Loader that provides an {@link AsyncTask} to do the work. See 329567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * {@link Loader} and {@link android.app.LoaderManager} for more details. 339567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * 349567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * <p>Here is an example implementation of an AsyncTaskLoader subclass that 359567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * loads the currently installed applications from the package manager. This 369567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * implementation takes care of retrieving the application labels and sorting 379567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * its result set from them, monitoring for changes to the installed 389567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * applications, and rebuilding the list when a change in configuration requires 399567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * this (such as a locale change). 409567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * 419567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LoaderCustom.java 429567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * loader} 439567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * 449567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * <p>An example implementation of a fragment that uses the above loader to show 459567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * the currently installed applications in a list is below. 469567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * 479567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LoaderCustom.java 489567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * fragment} 49bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov * 509911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * @param <D> the data type to be loaded. 519911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton */ 529911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamiltonpublic abstract class AsyncTaskLoader<D> extends Loader<D> { 53540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn static final String TAG = "AsyncTaskLoader"; 54540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn static final boolean DEBUG = false; 55cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov 56247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable { 57b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown private final CountDownLatch mDone = new CountDownLatch(1); 58bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov 59b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown // Set to true to indicate that the task has been posted to a handler for 60b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown // execution at a later time. Used to throttle updates. 61247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn boolean waiting; 62bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov 639911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton /* Runs on a worker thread */ 649911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton @Override 659911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton protected D doInBackground(Void... params) { 66540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn if (DEBUG) Slog.v(TAG, this + " >>> doInBackground"); 67b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown try { 68b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown D data = AsyncTaskLoader.this.onLoadInBackground(); 69b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown if (DEBUG) Slog.v(TAG, this + " <<< doInBackground"); 70b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown return data; 71b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown } catch (OperationCanceledException ex) { 72b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown if (!isCancelled()) { 73b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown // onLoadInBackground threw a canceled exception spuriously. 74b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown // This is problematic because it means that the LoaderManager did not 75b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown // cancel the Loader itself and still expects to receive a result. 76b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown // Additionally, the Loader's own state will not have been updated to 77b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown // reflect the fact that the task was being canceled. 78b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown // So we treat this case as an unhandled exception. 79b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown throw ex; 80b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown } 81b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown if (DEBUG) Slog.v(TAG, this + " <<< doInBackground (was canceled)"); 82b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown return null; 83b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown } 849911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton } 859911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton 869911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton /* Runs on the UI thread */ 879911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton @Override 889911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton protected void onPostExecute(D data) { 89540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn if (DEBUG) Slog.v(TAG, this + " onPostExecute"); 9059d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov try { 9159d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov AsyncTaskLoader.this.dispatchOnLoadComplete(this, data); 9259d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov } finally { 93b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown mDone.countDown(); 9459d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov } 959911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton } 96bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov 97b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown /* Runs on the UI thread */ 98bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov @Override 99b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown protected void onCancelled(D data) { 100540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn if (DEBUG) Slog.v(TAG, this + " onCancelled"); 10159d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov try { 102b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown AsyncTaskLoader.this.dispatchOnCancelled(this, data); 10359d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov } finally { 104b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown mDone.countDown(); 10559d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov } 106247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 107247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn 108b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown /* Runs on the UI thread, when the waiting task is posted to a handler. 109b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * This method is only executed when task execution was deferred (waiting was true). */ 110247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn @Override 111247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn public void run() { 112247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn waiting = false; 113247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn AsyncTaskLoader.this.executePendingTask(); 114bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov } 115b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown 116b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown /* Used for testing purposes to wait for the task to complete. */ 117b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown public void waitForLoader() { 118b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown try { 119b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown mDone.await(); 120b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown } catch (InterruptedException e) { 121b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown // Ignore 122b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown } 123b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown } 1249911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton } 1259911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton 126cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov volatile LoadTask mTask; 127247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn volatile LoadTask mCancellingTask; 128247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn 129247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn long mUpdateThrottle; 130247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn long mLastLoadCompleteTime = -10000; 131247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn Handler mHandler; 1329911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton 1339911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton public AsyncTaskLoader(Context context) { 1349911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton super(context); 1359911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton } 1369911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton 137247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn /** 138247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn * Set amount to throttle updates by. This is the minimum time from 139b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * when the last {@link #loadInBackground()} call has completed until 140247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn * a new load is scheduled. 141247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn * 142247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn * @param delayMS Amount of delay, in milliseconds. 143247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn */ 144247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn public void setUpdateThrottle(long delayMS) { 145247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mUpdateThrottle = delayMS; 146247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn if (delayMS != 0) { 147247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mHandler = new Handler(); 148247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 149247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 150247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn 1519911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton @Override 152a2ea747faaf5fcd437afbaaf4085cfc29e7c16b8Dianne Hackborn protected void onForceLoad() { 1530e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn super.onForceLoad(); 154bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov cancelLoad(); 1559911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton mTask = new LoadTask(); 156540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn if (DEBUG) Slog.v(TAG, "Preparing load: mTask=" + mTask); 157247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn executePendingTask(); 1589911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton } 1599911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton 160b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown @Override 161b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown protected boolean onCancelLoad() { 162b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown if (DEBUG) Slog.v(TAG, "onCancelLoad: mTask=" + mTask); 1639911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton if (mTask != null) { 164247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn if (mCancellingTask != null) { 165247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn // There was a pending task already waiting for a previous 166247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn // one being canceled; just drop it. 167540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn if (DEBUG) Slog.v(TAG, 168540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn "cancelLoad: still waiting for cancelled task; dropping next"); 169247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn if (mTask.waiting) { 170247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mTask.waiting = false; 171247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mHandler.removeCallbacks(mTask); 172247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 173247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mTask = null; 174247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn return false; 175247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } else if (mTask.waiting) { 176247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn // There is a task, but it is waiting for the time it should 177247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn // execute. We can just toss it. 178540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn if (DEBUG) Slog.v(TAG, "cancelLoad: task is waiting, dropping it"); 179247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mTask.waiting = false; 180247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mHandler.removeCallbacks(mTask); 181247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mTask = null; 182247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn return false; 183247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } else { 184247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn boolean cancelled = mTask.cancel(false); 185540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn if (DEBUG) Slog.v(TAG, "cancelLoad: cancelled=" + cancelled); 186247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn if (cancelled) { 187247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mCancellingTask = mTask; 188b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown cancelLoadInBackground(); 189247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 190247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mTask = null; 191247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn return cancelled; 192247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 1939911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton } 1949911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton return false; 1959911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton } 196bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov 197bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov /** 198bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov * Called if the task was canceled before it was completed. Gives the class a chance 199b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * to clean up post-cancellation and to properly dispose of the result. 200b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * 201b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * @param data The value that was returned by {@link #loadInBackground}, or null 202b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * if the task threw {@link OperationCanceledException}. 203bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov */ 204327fbd2c8fa294b919475feb4c74a74ee1981e02Dianne Hackborn public void onCanceled(D data) { 205327fbd2c8fa294b919475feb4c74a74ee1981e02Dianne Hackborn } 2064afde4fda383116a9730aea1e931d4bce7ea0fd0Dmitri Plotnikov 207247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn void executePendingTask() { 208247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn if (mCancellingTask == null && mTask != null) { 209247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn if (mTask.waiting) { 210247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mTask.waiting = false; 211247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mHandler.removeCallbacks(mTask); 212247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 213247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn if (mUpdateThrottle > 0) { 214247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn long now = SystemClock.uptimeMillis(); 215247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn if (now < (mLastLoadCompleteTime+mUpdateThrottle)) { 216247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn // Not yet time to do another load. 217540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn if (DEBUG) Slog.v(TAG, "Waiting until " 218540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn + (mLastLoadCompleteTime+mUpdateThrottle) 219540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn + " to execute: " + mTask); 220247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mTask.waiting = true; 221247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle); 222247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn return; 223247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 224247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 225540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn if (DEBUG) Slog.v(TAG, "Executing: " + mTask); 2265d9d03a0234faa3cffd11502f973057045cafe82Dianne Hackborn mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); 227247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 228247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 229247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn 230247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn void dispatchOnCancelled(LoadTask task, D data) { 231327fbd2c8fa294b919475feb4c74a74ee1981e02Dianne Hackborn onCanceled(data); 232247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn if (mCancellingTask == task) { 233540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn if (DEBUG) Slog.v(TAG, "Cancelled task is now canceled!"); 234247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mLastLoadCompleteTime = SystemClock.uptimeMillis(); 235247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn mCancellingTask = null; 236b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown if (DEBUG) Slog.v(TAG, "Delivering cancellation"); 237b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown deliverCancellation(); 238247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn executePendingTask(); 239247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 240247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 241247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn 2420e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn void dispatchOnLoadComplete(LoadTask task, D data) { 2430e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn if (mTask != task) { 244540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn if (DEBUG) Slog.v(TAG, "Load complete of old task, trying to cancel"); 245247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn dispatchOnCancelled(task, data); 2460e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn } else { 247260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn if (isAbandoned()) { 248260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn // This cursor has been abandoned; just cancel the new data. 249260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn onCanceled(data); 250260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn } else { 251260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn mLastLoadCompleteTime = SystemClock.uptimeMillis(); 252260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn mTask = null; 253260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn if (DEBUG) Slog.v(TAG, "Delivering result"); 254260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn deliverResult(data); 255260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn } 2560e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn } 2579911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton } 2589911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton 2599911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton /** 260b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * Called on a worker thread to perform the actual load and to return 261b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * the result of the load operation. 262b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * 263b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * Implementations should not deliver the result directly, but should return them 264b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * from this method, which will eventually end up calling {@link #deliverResult} on 265b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * the UI thread. If implementations need to process the results on the UI thread 266b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * they may override {@link #deliverResult} and do so there. 267b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * 268b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * To support cancellation, this method should periodically check the value of 269b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * {@link #isLoadInBackgroundCanceled} and terminate when it returns true. 270b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * Subclasses may also override {@link #cancelLoadInBackground} to interrupt the load 271b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * directly instead of polling {@link #isLoadInBackgroundCanceled}. 272b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * 273b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * When the load is canceled, this method may either return normally or throw 274b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * {@link OperationCanceledException}. In either case, the {@link Loader} will 275b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the 276b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * result object, if any. 277b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * 278b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * @return The result of the load operation. 279b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * 280b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * @throws OperationCanceledException if the load is canceled during execution. 281b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * 282b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * @see #isLoadInBackgroundCanceled 283b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * @see #cancelLoadInBackground 284b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * @see #onCanceled 285247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn */ 286247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn public abstract D loadInBackground(); 287247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn 288247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn /** 289b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * Calls {@link #loadInBackground()}. 290b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * 291b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * This method is reserved for use by the loader framework. 292b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * Subclasses should override {@link #loadInBackground} instead of this method. 293b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * 294b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * @return The result of the load operation. 2959911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * 296b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * @throws OperationCanceledException if the load is canceled during execution. 297b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * 298b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * @see #loadInBackground 2999911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton */ 300247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn protected D onLoadInBackground() { 301247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn return loadInBackground(); 302247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 303cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov 304cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov /** 305b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * Called on the main thread to abort a load in progress. 306b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * 307b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * Override this method to abort the current invocation of {@link #loadInBackground} 308b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * that is running in the background on a worker thread. 30975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * 310b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * This method should do nothing if {@link #loadInBackground} has not started 311b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * running or if it has already finished. 312b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * 313b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * @see #loadInBackground 31475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown */ 315b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown public void cancelLoadInBackground() { 31675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 31775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 31875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown /** 319b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * Returns true if the current invocation of {@link #loadInBackground} is being canceled. 320b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * 321b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * @return True if the current invocation of {@link #loadInBackground} is being canceled. 32275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * 323b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown * @see #loadInBackground 32475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown */ 325b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown public boolean isLoadInBackgroundCanceled() { 32675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return mCancellingTask != null; 32775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 32875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 32975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown /** 330cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov * Locks the current thread until the loader completes the current load 331cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov * operation. Returns immediately if there is no load operation running. 33259d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov * Should not be called from the UI thread: calling it from the UI 33359d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov * thread would cause a deadlock. 334cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov * <p> 335247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn * Use for testing only. <b>Never</b> call this from a UI thread. 3364afde4fda383116a9730aea1e931d4bce7ea0fd0Dmitri Plotnikov * 3374afde4fda383116a9730aea1e931d4bce7ea0fd0Dmitri Plotnikov * @hide 338cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov */ 339cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov public void waitForLoader() { 340cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov LoadTask task = mTask; 341cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov if (task != null) { 342b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown task.waitForLoader(); 343cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov } 344cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov } 345247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn 346247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn @Override 347247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 348247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn super.dump(prefix, fd, writer, args); 349247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn if (mTask != null) { 350247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn writer.print(prefix); writer.print("mTask="); writer.print(mTask); 351247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn writer.print(" waiting="); writer.println(mTask.waiting); 352247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 353247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn if (mCancellingTask != null) { 354247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn writer.print(prefix); writer.print("mCancellingTask="); writer.print(mCancellingTask); 355247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn writer.print(" waiting="); writer.println(mCancellingTask.waiting); 356247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 357247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn if (mUpdateThrottle != 0) { 358247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn writer.print(prefix); writer.print("mUpdateThrottle="); 359247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn TimeUtils.formatDuration(mUpdateThrottle, writer); 360247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn writer.print(" mLastLoadCompleteTime="); 361247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn TimeUtils.formatDuration(mLastLoadCompleteTime, 362247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn SystemClock.uptimeMillis(), writer); 363247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn writer.println(); 364247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 365247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn } 3669911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton} 367