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