1cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn/* 2cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Copyright (C) 2011 The Android Open Source Project 3cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * 4cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 5cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * you may not use this file except in compliance with the License. 6cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * You may obtain a copy of the License at 7cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * 8cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 9cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * 10cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Unless required by applicable law or agreed to in writing, software 11cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 12cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * See the License for the specific language governing permissions and 14cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * limitations under the License. 15cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */ 16cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 17cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornpackage android.support.v4.content; 18cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 198e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikasimport static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; 208e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas 21cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.content.Context; 22cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.os.Handler; 23cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.os.SystemClock; 24c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport android.support.annotation.RestrictTo; 25220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownimport android.support.v4.os.OperationCanceledException; 26cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.support.v4.util.TimeUtils; 27cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.util.Log; 28cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 29cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport java.io.FileDescriptor; 30cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport java.io.PrintWriter; 31cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport java.util.concurrent.CountDownLatch; 32220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownimport java.util.concurrent.Executor; 33cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 34cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn/** 35cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Static library support version of the framework's {@link android.content.AsyncTaskLoader}. 36cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Used to write apps that run on platforms prior to Android 3.0. When running 37cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * on Android 3.0 or above, this implementation is still used; it does not try 38cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * to switch to the framework's implementation. See the framework SDK 39cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * documentation for a class overview. 40cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */ 41cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornpublic abstract class AsyncTaskLoader<D> extends Loader<D> { 42cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn static final String TAG = "AsyncTaskLoader"; 43cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn static final boolean DEBUG = false; 44cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 45fbabff99ccbcb576c713991c5db5dec21a0d0ce0Dianne Hackborn final class LoadTask extends ModernAsyncTask<Void, Void, D> implements Runnable { 46220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown private final CountDownLatch mDone = new CountDownLatch(1); 47cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 48220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown // Set to true to indicate that the task has been posted to a handler for 49220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown // execution at a later time. Used to throttle updates. 50cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn boolean waiting; 51cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 52cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn /* Runs on a worker thread */ 53cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn @Override 54cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn protected D doInBackground(Void... params) { 55cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (DEBUG) Log.v(TAG, this + " >>> doInBackground"); 56220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown try { 57220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown D data = AsyncTaskLoader.this.onLoadInBackground(); 58220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown if (DEBUG) Log.v(TAG, this + " <<< doInBackground"); 59220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown return data; 60220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown } catch (OperationCanceledException ex) { 61220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown if (!isCancelled()) { 62220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown // onLoadInBackground threw a canceled exception spuriously. 63220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown // This is problematic because it means that the LoaderManager did not 64220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown // cancel the Loader itself and still expects to receive a result. 65220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown // Additionally, the Loader's own state will not have been updated to 66220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown // reflect the fact that the task was being canceled. 67220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown // So we treat this case as an unhandled exception. 68220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown throw ex; 69220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown } 70220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown if (DEBUG) Log.v(TAG, this + " <<< doInBackground (was canceled)", ex); 71220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown return null; 72220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown } 73cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 74cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 75cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn /* Runs on the UI thread */ 76cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn @Override 77cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn protected void onPostExecute(D data) { 78cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (DEBUG) Log.v(TAG, this + " onPostExecute"); 79cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn try { 80cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn AsyncTaskLoader.this.dispatchOnLoadComplete(this, data); 81cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } finally { 82220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown mDone.countDown(); 83cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 84cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 85cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 86220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown /* Runs on the UI thread */ 87cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn @Override 88220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown protected void onCancelled(D data) { 89cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (DEBUG) Log.v(TAG, this + " onCancelled"); 90cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn try { 91220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown AsyncTaskLoader.this.dispatchOnCancelled(this, data); 92cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } finally { 93220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown mDone.countDown(); 94cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 95cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 96cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 97220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown /* Runs on the UI thread, when the waiting task is posted to a handler. 98220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * This method is only executed when task execution was deferred (waiting was true). */ 99cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn @Override 100cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn public void run() { 101cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn waiting = false; 102cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn AsyncTaskLoader.this.executePendingTask(); 103cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 104220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown 105220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown /* Used for testing purposes to wait for the task to complete. */ 106220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown public void waitForLoader() { 107220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown try { 108220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown mDone.await(); 109220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown } catch (InterruptedException e) { 110220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown // Ignore 111220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown } 112220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown } 113cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 114cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 115220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown private final Executor mExecutor; 116220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown 117cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn volatile LoadTask mTask; 118cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn volatile LoadTask mCancellingTask; 119cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 120cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn long mUpdateThrottle; 121cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn long mLastLoadCompleteTime = -10000; 122cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn Handler mHandler; 123cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 124cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn public AsyncTaskLoader(Context context) { 125220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown this(context, ModernAsyncTask.THREAD_POOL_EXECUTOR); 126220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown } 127220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown 128220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown private AsyncTaskLoader(Context context, Executor executor) { 129cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn super(context); 130220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown mExecutor = executor; 131cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 132cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 133cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn /** 134cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Set amount to throttle updates by. This is the minimum time from 135220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * when the last {@link #loadInBackground()} call has completed until 136cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * a new load is scheduled. 137cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * 138cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * @param delayMS Amount of delay, in milliseconds. 139cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */ 140cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn public void setUpdateThrottle(long delayMS) { 141cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mUpdateThrottle = delayMS; 142cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (delayMS != 0) { 143cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mHandler = new Handler(); 144cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 145cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 146cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 147cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn @Override 148cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn protected void onForceLoad() { 149cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn super.onForceLoad(); 150cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn cancelLoad(); 151cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mTask = new LoadTask(); 152cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask); 153cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn executePendingTask(); 154cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 155cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 156220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown @Override 157220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown protected boolean onCancelLoad() { 158220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown if (DEBUG) Log.v(TAG, "onCancelLoad: mTask=" + mTask); 159cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (mTask != null) { 16068e91a863a33bd9bca500f0c8bce38014b5018b9George Mount if (!mStarted) { 16168e91a863a33bd9bca500f0c8bce38014b5018b9George Mount mContentChanged = true; 16268e91a863a33bd9bca500f0c8bce38014b5018b9George Mount } 163cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (mCancellingTask != null) { 164cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn // There was a pending task already waiting for a previous 165cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn // one being canceled; just drop it. 166cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (DEBUG) Log.v(TAG, 167cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn "cancelLoad: still waiting for cancelled task; dropping next"); 168cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (mTask.waiting) { 169cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mTask.waiting = false; 170cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mHandler.removeCallbacks(mTask); 171cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 172cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mTask = null; 173cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn return false; 174cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } else if (mTask.waiting) { 175cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn // There is a task, but it is waiting for the time it should 176cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn // execute. We can just toss it. 177cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (DEBUG) Log.v(TAG, "cancelLoad: task is waiting, dropping it"); 178cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mTask.waiting = false; 179cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mHandler.removeCallbacks(mTask); 180cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mTask = null; 181cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn return false; 182cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } else { 183cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn boolean cancelled = mTask.cancel(false); 184cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (DEBUG) Log.v(TAG, "cancelLoad: cancelled=" + cancelled); 185cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (cancelled) { 186cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mCancellingTask = mTask; 187220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown cancelLoadInBackground(); 188cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 189cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mTask = null; 190cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn return cancelled; 191cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 192cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 193cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn return false; 194cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 195cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 196cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn /** 197cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Called if the task was canceled before it was completed. Gives the class a chance 198220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * to clean up post-cancellation and to properly dispose of the result. 199220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 200220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * @param data The value that was returned by {@link #loadInBackground}, or null 201220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * if the task threw {@link OperationCanceledException}. 202cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */ 203cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn public void onCanceled(D data) { 204cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 205cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 206cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn void executePendingTask() { 207cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (mCancellingTask == null && mTask != null) { 208cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (mTask.waiting) { 209cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mTask.waiting = false; 210cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mHandler.removeCallbacks(mTask); 211cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 212cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (mUpdateThrottle > 0) { 213cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn long now = SystemClock.uptimeMillis(); 214cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (now < (mLastLoadCompleteTime+mUpdateThrottle)) { 215cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn // Not yet time to do another load. 216cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (DEBUG) Log.v(TAG, "Waiting until " 217cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn + (mLastLoadCompleteTime+mUpdateThrottle) 218cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn + " to execute: " + mTask); 219cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mTask.waiting = true; 220cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle); 221cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn return; 222cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 223cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 224cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (DEBUG) Log.v(TAG, "Executing: " + mTask); 225220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown mTask.executeOnExecutor(mExecutor, (Void[]) null); 226cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 227cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 228cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 229cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn void dispatchOnCancelled(LoadTask task, D data) { 230cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn onCanceled(data); 231cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (mCancellingTask == task) { 232cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (DEBUG) Log.v(TAG, "Cancelled task is now canceled!"); 23380a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn rollbackContentChanged(); 234cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mLastLoadCompleteTime = SystemClock.uptimeMillis(); 235cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mCancellingTask = null; 236220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown if (DEBUG) Log.v(TAG, "Delivering cancellation"); 237220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown deliverCancellation(); 238cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn executePendingTask(); 239cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 240cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 241cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 242cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn void dispatchOnLoadComplete(LoadTask task, D data) { 243cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (mTask != task) { 244cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (DEBUG) Log.v(TAG, "Load complete of old task, trying to cancel"); 245cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn dispatchOnCancelled(task, data); 246cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } else { 247cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (isAbandoned()) { 248cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn // This cursor has been abandoned; just cancel the new data. 249cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn onCanceled(data); 250cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } else { 25180a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn commitContentChanged(); 252cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mLastLoadCompleteTime = SystemClock.uptimeMillis(); 253cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn mTask = null; 254cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (DEBUG) Log.v(TAG, "Delivering result"); 255cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn deliverResult(data); 256cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 257cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 258cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 259cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 260cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn /** 261220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Called on a worker thread to perform the actual load and to return 262220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * the result of the load operation. 263220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 264220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Implementations should not deliver the result directly, but should return them 265220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * from this method, which will eventually end up calling {@link #deliverResult} on 266220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * the UI thread. If implementations need to process the results on the UI thread 267220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * they may override {@link #deliverResult} and do so there. 268220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 269220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * To support cancellation, this method should periodically check the value of 270220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * {@link #isLoadInBackgroundCanceled} and terminate when it returns true. 271220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Subclasses may also override {@link #cancelLoadInBackground} to interrupt the load 272220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * directly instead of polling {@link #isLoadInBackgroundCanceled}. 273220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 274220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * When the load is canceled, this method may either return normally or throw 275220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * {@link OperationCanceledException}. In either case, the {@link Loader} will 276220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the 277220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * result object, if any. 278220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 279220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * @return The result of the load operation. 280220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 281220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * @throws OperationCanceledException if the load is canceled during execution. 282220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 283220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * @see #isLoadInBackgroundCanceled 284220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * @see #cancelLoadInBackground 285220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * @see #onCanceled 286cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */ 287cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn public abstract D loadInBackground(); 288cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 289cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn /** 290220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Calls {@link #loadInBackground()}. 291220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 292220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * This method is reserved for use by the loader framework. 293220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Subclasses should override {@link #loadInBackground} instead of this method. 294220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 295220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * @return The result of the load operation. 296220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 297220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * @throws OperationCanceledException if the load is canceled during execution. 298cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * 299220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * @see #loadInBackground 300cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */ 301cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn protected D onLoadInBackground() { 302cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn return loadInBackground(); 303cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 304cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 305cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn /** 306220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Called on the main thread to abort a load in progress. 307220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 308220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Override this method to abort the current invocation of {@link #loadInBackground} 309220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * that is running in the background on a worker thread. 310220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 311220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * This method should do nothing if {@link #loadInBackground} has not started 312220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * running or if it has already finished. 313220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 314220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * @see #loadInBackground 315220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown */ 316220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown public void cancelLoadInBackground() { 317220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown } 318220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown 319220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown /** 320220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Returns true if the current invocation of {@link #loadInBackground} is being canceled. 321220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 322220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * @return True if the current invocation of {@link #loadInBackground} is being canceled. 323220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * 324220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * @see #loadInBackground 325220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown */ 326220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown public boolean isLoadInBackgroundCanceled() { 327220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown return mCancellingTask != null; 328220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown } 329220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown 330220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown /** 331cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Locks the current thread until the loader completes the current load 332cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * operation. Returns immediately if there is no load operation running. 333cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Should not be called from the UI thread: calling it from the UI 334cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * thread would cause a deadlock. 335cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * <p> 336cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Use for testing only. <b>Never</b> call this from a UI thread. 337cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * 338cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * @hide 339cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */ 3408e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas @RestrictTo(LIBRARY_GROUP) 341cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn public void waitForLoader() { 342cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn LoadTask task = mTask; 343cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (task != null) { 344220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown task.waitForLoader(); 345cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 346cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 347cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn 348cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn @Override 349cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 350cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn super.dump(prefix, fd, writer, args); 351cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (mTask != null) { 352cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn writer.print(prefix); writer.print("mTask="); writer.print(mTask); 353cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn writer.print(" waiting="); writer.println(mTask.waiting); 354cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 355cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (mCancellingTask != null) { 356cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn writer.print(prefix); writer.print("mCancellingTask="); writer.print(mCancellingTask); 357cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn writer.print(" waiting="); writer.println(mCancellingTask.waiting); 358cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 359cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn if (mUpdateThrottle != 0) { 360cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn writer.print(prefix); writer.print("mUpdateThrottle="); 361cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn TimeUtils.formatDuration(mUpdateThrottle, writer); 362cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn writer.print(" mLastLoadCompleteTime="); 363cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn TimeUtils.formatDuration(mLastLoadCompleteTime, 364cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn SystemClock.uptimeMillis(), writer); 365cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn writer.println(); 366cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 367cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn } 368cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn} 369