1 /* 2 * This is an adapted version of Android's original CursorLoader 3 * without all the ContentProvider-specific bits. 4 * 5 * Copyright (C) 2011 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 package org.mozilla.gecko.home; 21 22 import android.content.Context; 23 import android.database.Cursor; 24 import android.support.v4.content.AsyncTaskLoader; 25 26 import org.mozilla.gecko.GeckoApplication; 27 28 /** 29 * A copy of the framework's {@link android.content.CursorLoader} that 30 * instead allows the caller to load the Cursor themselves via the abstract 31 * {@link #loadCursor()} method, rather than calling out to a ContentProvider via 32 * class methods. 33 * 34 * For new code, prefer {@link android.content.CursorLoader} (see @deprecated). 35 * 36 * This was originally created to re-use existing code which loaded Cursors manually. 37 * 38 * @deprecated since the framework provides an implementation, we'd like to eventually remove 39 * this class to reduce maintenance burden. Originally planned for bug 1239491, but 40 * it'd be more efficient to do this over time, rather than all at once. 41 */ 42 @Deprecated 43 public abstract class SimpleCursorLoader extends AsyncTaskLoader<Cursor> { 44 final ForceLoadContentObserver mObserver; 45 Cursor mCursor; 46 SimpleCursorLoader(Context context)47 public SimpleCursorLoader(Context context) { 48 super(context); 49 mObserver = new ForceLoadContentObserver(); 50 } 51 52 /** 53 * Loads the target cursor for this loader. This method is called 54 * on a worker thread. 55 */ loadCursor()56 protected abstract Cursor loadCursor(); 57 58 /* Runs on a worker thread */ 59 @Override loadInBackground()60 public Cursor loadInBackground() { 61 Cursor cursor = loadCursor(); 62 63 if (cursor != null) { 64 // Ensure the cursor window is filled 65 cursor.getCount(); 66 cursor.registerContentObserver(mObserver); 67 } 68 69 return cursor; 70 } 71 72 /* Runs on the UI thread */ 73 @Override deliverResult(Cursor cursor)74 public void deliverResult(Cursor cursor) { 75 if (isReset()) { 76 // An async query came in while the loader is stopped 77 if (cursor != null) { 78 cursor.close(); 79 } 80 81 return; 82 } 83 84 Cursor oldCursor = mCursor; 85 mCursor = cursor; 86 87 if (isStarted()) { 88 super.deliverResult(cursor); 89 } 90 91 if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) { 92 oldCursor.close(); 93 94 // Trying to read from the closed cursor will cause crashes, hence we should make 95 // sure that no adapters/LoaderCallbacks are holding onto this cursor. 96 GeckoApplication.getRefWatcher(getContext()).watch(oldCursor); 97 } 98 } 99 100 /** 101 * Starts an asynchronous load of the list data. When the result is ready the callbacks 102 * will be called on the UI thread. If a previous load has been completed and is still valid 103 * the result may be passed to the callbacks immediately. 104 * 105 * Must be called from the UI thread 106 */ 107 @Override onStartLoading()108 protected void onStartLoading() { 109 if (mCursor != null) { 110 deliverResult(mCursor); 111 } 112 113 if (takeContentChanged() || mCursor == null) { 114 forceLoad(); 115 } 116 } 117 118 /** 119 * Must be called from the UI thread 120 */ 121 @Override onStopLoading()122 protected void onStopLoading() { 123 // Attempt to cancel the current load task if possible. 124 cancelLoad(); 125 } 126 127 @Override onCanceled(Cursor cursor)128 public void onCanceled(Cursor cursor) { 129 if (cursor != null && !cursor.isClosed()) { 130 cursor.close(); 131 } 132 } 133 134 @Override onReset()135 protected void onReset() { 136 super.onReset(); 137 138 // Ensure the loader is stopped 139 onStopLoading(); 140 141 if (mCursor != null && !mCursor.isClosed()) { 142 mCursor.close(); 143 } 144 145 mCursor = null; 146 } 147 }