blob: 5d7d67743a7d800437c1b2ee3397843a5c43fa2e [file] [log] [blame]
Jeff Hamilton9911b7f2010-05-15 02:20:31 -05001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.content;
18
Dmitri Plotnikov4d891e72010-09-22 11:04:10 -070019import android.database.ContentObserver;
Jeff Hamilton9911b7f2010-05-15 02:20:31 -050020import android.database.Cursor;
21import android.net.Uri;
Jeff Browna7771df2012-05-07 20:06:46 -070022import android.os.CancellationSignal;
23import android.os.OperationCanceledException;
Jeff Hamilton9911b7f2010-05-15 02:20:31 -050024
Dianne Hackborna2ea7472010-12-20 12:10:01 -080025import java.io.FileDescriptor;
26import java.io.PrintWriter;
27import java.util.Arrays;
28
Jeff Hamilton9911b7f2010-05-15 02:20:31 -050029/**
30 * A loader that queries the {@link ContentResolver} and returns a {@link Cursor}.
Dianne Hackborn327fbd22011-01-17 14:38:50 -080031 * This class implements the {@link Loader} protocol in a standard way for
32 * querying cursors, building on {@link AsyncTaskLoader} to perform the cursor
33 * query on a background thread so that it does not block the application's UI.
34 *
35 * <p>A CursorLoader must be built with the full information for the query to
36 * perform, either through the
37 * {@link #CursorLoader(Context, Uri, String[], String, String[], String)} or
38 * creating an empty instance with {@link #CursorLoader(Context)} and filling
39 * in the desired paramters with {@link #setUri(Uri)}, {@link #setSelection(String)},
40 * {@link #setSelectionArgs(String[])}, {@link #setSortOrder(String)},
41 * and {@link #setProjection(String[])}.
Jeff Hamilton9911b7f2010-05-15 02:20:31 -050042 */
43public class CursorLoader extends AsyncTaskLoader<Cursor> {
Dianne Hackborna2ea7472010-12-20 12:10:01 -080044 final ForceLoadContentObserver mObserver;
45
Jeff Hamilton9911b7f2010-05-15 02:20:31 -050046 Uri mUri;
47 String[] mProjection;
48 String mSelection;
49 String[] mSelectionArgs;
50 String mSortOrder;
51
Dianne Hackborna2ea7472010-12-20 12:10:01 -080052 Cursor mCursor;
Jeff Brown4c1241d2012-02-02 17:05:00 -080053 CancellationSignal mCancellationSignal;
Dianne Hackborna2ea7472010-12-20 12:10:01 -080054
Jeff Hamilton9911b7f2010-05-15 02:20:31 -050055 /* Runs on a worker thread */
56 @Override
57 public Cursor loadInBackground() {
Jeff Brown75ea64f2012-01-25 19:37:13 -080058 synchronized (this) {
59 if (isLoadInBackgroundCanceled()) {
60 throw new OperationCanceledException();
61 }
Jeff Brown4c1241d2012-02-02 17:05:00 -080062 mCancellationSignal = new CancellationSignal();
Jeff Hamilton9911b7f2010-05-15 02:20:31 -050063 }
Jeff Brown75ea64f2012-01-25 19:37:13 -080064 try {
65 Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
Jeff Brown4c1241d2012-02-02 17:05:00 -080066 mSelectionArgs, mSortOrder, mCancellationSignal);
Jeff Brown75ea64f2012-01-25 19:37:13 -080067 if (cursor != null) {
Jeff Brownc21b5a02013-01-07 17:15:12 -080068 try {
69 // Ensure the cursor window is filled.
70 cursor.getCount();
Scott Kennedyda2223f2013-03-13 14:40:11 -070071 cursor.registerContentObserver(mObserver);
Jeff Brownc21b5a02013-01-07 17:15:12 -080072 } catch (RuntimeException ex) {
73 cursor.close();
74 throw ex;
75 }
Jeff Brown75ea64f2012-01-25 19:37:13 -080076 }
77 return cursor;
78 } finally {
79 synchronized (this) {
Jeff Brown4c1241d2012-02-02 17:05:00 -080080 mCancellationSignal = null;
Jeff Brown75ea64f2012-01-25 19:37:13 -080081 }
82 }
83 }
84
85 @Override
Jeff Brownb19a71a2012-01-31 11:48:39 -080086 public void cancelLoadInBackground() {
87 super.cancelLoadInBackground();
Jeff Brown75ea64f2012-01-25 19:37:13 -080088
89 synchronized (this) {
Jeff Brown4c1241d2012-02-02 17:05:00 -080090 if (mCancellationSignal != null) {
91 mCancellationSignal.cancel();
Jeff Brown75ea64f2012-01-25 19:37:13 -080092 }
93 }
Jeff Hamilton9911b7f2010-05-15 02:20:31 -050094 }
95
96 /* Runs on the UI thread */
97 @Override
98 public void deliverResult(Cursor cursor) {
Dianne Hackborn0e3b8f422010-12-20 23:22:11 -080099 if (isReset()) {
Jeff Hamilton9911b7f2010-05-15 02:20:31 -0500100 // An async query came in while the loader is stopped
Dmitri Plotnikov4565d522010-07-15 18:24:07 -0700101 if (cursor != null) {
Dianne Hackborn229edbc2011-10-09 16:01:40 -0700102 cursor.close();
Dmitri Plotnikov4565d522010-07-15 18:24:07 -0700103 }
Jeff Hamilton9911b7f2010-05-15 02:20:31 -0500104 return;
105 }
Ben Komalo8e6f69b2010-07-22 16:21:22 -0700106 Cursor oldCursor = mCursor;
Jeff Hamilton9911b7f2010-05-15 02:20:31 -0500107 mCursor = cursor;
Ben Komalo8e6f69b2010-07-22 16:21:22 -0700108
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800109 if (isStarted()) {
Dianne Hackbornc9189352010-12-15 14:57:25 -0800110 super.deliverResult(cursor);
111 }
112
113 if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
Dianne Hackborn229edbc2011-10-09 16:01:40 -0700114 oldCursor.close();
Ben Komalo8e6f69b2010-07-22 16:21:22 -0700115 }
Jeff Hamilton9911b7f2010-05-15 02:20:31 -0500116 }
117
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800118 /**
119 * Creates an empty unspecified CursorLoader. You must follow this with
120 * calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc
121 * to specify the query to perform.
122 */
123 public CursorLoader(Context context) {
124 super(context);
125 mObserver = new ForceLoadContentObserver();
126 }
127
128 /**
129 * Creates a fully-specified CursorLoader. See
130 * {@link ContentResolver#query(Uri, String[], String, String[], String)
131 * ContentResolver.query()} for documentation on the meaning of the
132 * parameters. These will be passed as-is to that call.
133 */
Jeff Hamilton9911b7f2010-05-15 02:20:31 -0500134 public CursorLoader(Context context, Uri uri, String[] projection, String selection,
135 String[] selectionArgs, String sortOrder) {
136 super(context);
137 mObserver = new ForceLoadContentObserver();
138 mUri = uri;
139 mProjection = projection;
140 mSelection = selection;
141 mSelectionArgs = selectionArgs;
142 mSortOrder = sortOrder;
143 }
144
145 /**
146 * Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
147 * will be called on the UI thread. If a previous load has been completed and is still valid
Dmitri Plotnikovbef9c7a2010-06-16 15:38:07 -0700148 * the result may be passed to the callbacks immediately.
Jeff Hamilton9911b7f2010-05-15 02:20:31 -0500149 *
150 * Must be called from the UI thread
151 */
152 @Override
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800153 protected void onStartLoading() {
Jeff Hamilton9911b7f2010-05-15 02:20:31 -0500154 if (mCursor != null) {
155 deliverResult(mCursor);
Dianne Hackbornf73c75c2010-12-17 16:54:05 -0800156 }
Dianne Hackborn0e3b8f422010-12-20 23:22:11 -0800157 if (takeContentChanged() || mCursor == null) {
Jeff Hamilton9911b7f2010-05-15 02:20:31 -0500158 forceLoad();
159 }
160 }
161
162 /**
163 * Must be called from the UI thread
164 */
165 @Override
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800166 protected void onStopLoading() {
Jeff Hamilton9911b7f2010-05-15 02:20:31 -0500167 // Attempt to cancel the current load task if possible.
168 cancelLoad();
Jeff Hamilton9911b7f2010-05-15 02:20:31 -0500169 }
170
171 @Override
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800172 public void onCanceled(Cursor cursor) {
Dmitri Plotnikovbef9c7a2010-06-16 15:38:07 -0700173 if (cursor != null && !cursor.isClosed()) {
Dianne Hackborn229edbc2011-10-09 16:01:40 -0700174 cursor.close();
Dmitri Plotnikovbef9c7a2010-06-16 15:38:07 -0700175 }
176 }
177
178 @Override
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800179 protected void onReset() {
Dianne Hackborn0e3b8f422010-12-20 23:22:11 -0800180 super.onReset();
181
Jeff Hamilton9911b7f2010-05-15 02:20:31 -0500182 // Ensure the loader is stopped
Dianne Hackborn0e3b8f422010-12-20 23:22:11 -0800183 onStopLoading();
Dianne Hackbornc9189352010-12-15 14:57:25 -0800184
185 if (mCursor != null && !mCursor.isClosed()) {
Dianne Hackborn229edbc2011-10-09 16:01:40 -0700186 mCursor.close();
Dianne Hackbornc9189352010-12-15 14:57:25 -0800187 }
188 mCursor = null;
Jeff Hamilton9911b7f2010-05-15 02:20:31 -0500189 }
190
191 public Uri getUri() {
192 return mUri;
193 }
194
195 public void setUri(Uri uri) {
196 mUri = uri;
197 }
198
199 public String[] getProjection() {
200 return mProjection;
201 }
202
203 public void setProjection(String[] projection) {
204 mProjection = projection;
205 }
206
207 public String getSelection() {
208 return mSelection;
209 }
210
211 public void setSelection(String selection) {
212 mSelection = selection;
213 }
214
215 public String[] getSelectionArgs() {
216 return mSelectionArgs;
217 }
218
219 public void setSelectionArgs(String[] selectionArgs) {
220 mSelectionArgs = selectionArgs;
221 }
222
223 public String getSortOrder() {
224 return mSortOrder;
225 }
226
227 public void setSortOrder(String sortOrder) {
228 mSortOrder = sortOrder;
229 }
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800230
231 @Override
232 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
233 super.dump(prefix, fd, writer, args);
234 writer.print(prefix); writer.print("mUri="); writer.println(mUri);
235 writer.print(prefix); writer.print("mProjection=");
236 writer.println(Arrays.toString(mProjection));
237 writer.print(prefix); writer.print("mSelection="); writer.println(mSelection);
238 writer.print(prefix); writer.print("mSelectionArgs=");
239 writer.println(Arrays.toString(mSelectionArgs));
240 writer.print(prefix); writer.print("mSortOrder="); writer.println(mSortOrder);
241 writer.print(prefix); writer.print("mCursor="); writer.println(mCursor);
242 writer.print(prefix); writer.print("mContentChanged="); writer.println(mContentChanged);
243 }
Jeff Hamilton9911b7f2010-05-15 02:20:31 -0500244}