1 /*
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 
17 package android.content;
18 
19 import android.compat.annotation.UnsupportedAppUsage;
20 import android.database.Cursor;
21 import android.net.Uri;
22 import android.os.CancellationSignal;
23 import android.os.OperationCanceledException;
24 
25 import java.io.FileDescriptor;
26 import java.io.PrintWriter;
27 import java.util.Arrays;
28 
29 /**
30  * A loader that queries the {@link ContentResolver} and returns a {@link Cursor}.
31  * 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 parameters with {@link #setUri(Uri)}, {@link #setSelection(String)},
40  * {@link #setSelectionArgs(String[])}, {@link #setSortOrder(String)},
41  * and {@link #setProjection(String[])}.
42  *
43  * @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
44  *      {@link android.support.v4.content.CursorLoader}
45  */
46 @Deprecated
47 public class CursorLoader extends AsyncTaskLoader<Cursor> {
48     @UnsupportedAppUsage
49     final ForceLoadContentObserver mObserver;
50 
51     Uri mUri;
52     String[] mProjection;
53     String mSelection;
54     String[] mSelectionArgs;
55     String mSortOrder;
56 
57     Cursor mCursor;
58     @UnsupportedAppUsage
59     CancellationSignal mCancellationSignal;
60 
61     /* Runs on a worker thread */
62     @Override
loadInBackground()63     public Cursor loadInBackground() {
64         synchronized (this) {
65             if (isLoadInBackgroundCanceled()) {
66                 throw new OperationCanceledException();
67             }
68             mCancellationSignal = new CancellationSignal();
69         }
70         try {
71             Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
72                     mSelectionArgs, mSortOrder, mCancellationSignal);
73             if (cursor != null) {
74                 try {
75                     // Ensure the cursor window is filled.
76                     cursor.getCount();
77                     cursor.registerContentObserver(mObserver);
78                 } catch (RuntimeException ex) {
79                     cursor.close();
80                     throw ex;
81                 }
82             }
83             return cursor;
84         } finally {
85             synchronized (this) {
86                 mCancellationSignal = null;
87             }
88         }
89     }
90 
91     @Override
cancelLoadInBackground()92     public void cancelLoadInBackground() {
93         super.cancelLoadInBackground();
94 
95         synchronized (this) {
96             if (mCancellationSignal != null) {
97                 mCancellationSignal.cancel();
98             }
99         }
100     }
101 
102     /* Runs on the UI thread */
103     @Override
deliverResult(Cursor cursor)104     public void deliverResult(Cursor cursor) {
105         if (isReset()) {
106             // An async query came in while the loader is stopped
107             if (cursor != null) {
108                 cursor.close();
109             }
110             return;
111         }
112         Cursor oldCursor = mCursor;
113         mCursor = cursor;
114 
115         if (isStarted()) {
116             super.deliverResult(cursor);
117         }
118 
119         if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
120             oldCursor.close();
121         }
122     }
123 
124     /**
125      * Creates an empty unspecified CursorLoader.  You must follow this with
126      * calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc
127      * to specify the query to perform.
128      */
CursorLoader(Context context)129     public CursorLoader(Context context) {
130         super(context);
131         mObserver = new ForceLoadContentObserver();
132     }
133 
134     /**
135      * Creates a fully-specified CursorLoader.  See
136      * {@link ContentResolver#query(Uri, String[], String, String[], String)
137      * ContentResolver.query()} for documentation on the meaning of the
138      * parameters.  These will be passed as-is to that call.
139      */
CursorLoader(Context context, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)140     public CursorLoader(Context context, Uri uri, String[] projection, String selection,
141             String[] selectionArgs, String sortOrder) {
142         super(context);
143         mObserver = new ForceLoadContentObserver();
144         mUri = uri;
145         mProjection = projection;
146         mSelection = selection;
147         mSelectionArgs = selectionArgs;
148         mSortOrder = sortOrder;
149     }
150 
151     /**
152      * Starts an asynchronous load of the data. When the result is ready the callbacks
153      * will be called on the UI thread. If a previous load has been completed and is still valid
154      * the result may be passed to the callbacks immediately.
155      *
156      * Must be called from the UI thread
157      */
158     @Override
onStartLoading()159     protected void onStartLoading() {
160         if (mCursor != null) {
161             deliverResult(mCursor);
162         }
163         if (takeContentChanged() || mCursor == null) {
164             forceLoad();
165         }
166     }
167 
168     /**
169      * Must be called from the UI thread
170      */
171     @Override
onStopLoading()172     protected void onStopLoading() {
173         // Attempt to cancel the current load task if possible.
174         cancelLoad();
175     }
176 
177     @Override
onCanceled(Cursor cursor)178     public void onCanceled(Cursor cursor) {
179         if (cursor != null && !cursor.isClosed()) {
180             cursor.close();
181         }
182     }
183 
184     @Override
onReset()185     protected void onReset() {
186         super.onReset();
187 
188         // Ensure the loader is stopped
189         onStopLoading();
190 
191         if (mCursor != null && !mCursor.isClosed()) {
192             mCursor.close();
193         }
194         mCursor = null;
195     }
196 
getUri()197     public Uri getUri() {
198         return mUri;
199     }
200 
setUri(Uri uri)201     public void setUri(Uri uri) {
202         mUri = uri;
203     }
204 
getProjection()205     public String[] getProjection() {
206         return mProjection;
207     }
208 
setProjection(String[] projection)209     public void setProjection(String[] projection) {
210         mProjection = projection;
211     }
212 
getSelection()213     public String getSelection() {
214         return mSelection;
215     }
216 
setSelection(String selection)217     public void setSelection(String selection) {
218         mSelection = selection;
219     }
220 
getSelectionArgs()221     public String[] getSelectionArgs() {
222         return mSelectionArgs;
223     }
224 
setSelectionArgs(String[] selectionArgs)225     public void setSelectionArgs(String[] selectionArgs) {
226         mSelectionArgs = selectionArgs;
227     }
228 
getSortOrder()229     public String getSortOrder() {
230         return mSortOrder;
231     }
232 
setSortOrder(String sortOrder)233     public void setSortOrder(String sortOrder) {
234         mSortOrder = sortOrder;
235     }
236 
237     @Override
dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)238     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
239         super.dump(prefix, fd, writer, args);
240         writer.print(prefix); writer.print("mUri="); writer.println(mUri);
241         writer.print(prefix); writer.print("mProjection=");
242                 writer.println(Arrays.toString(mProjection));
243         writer.print(prefix); writer.print("mSelection="); writer.println(mSelection);
244         writer.print(prefix); writer.print("mSelectionArgs=");
245                 writer.println(Arrays.toString(mSelectionArgs));
246         writer.print(prefix); writer.print("mSortOrder="); writer.println(mSortOrder);
247         writer.print(prefix); writer.print("mCursor="); writer.println(mCursor);
248         writer.print(prefix); writer.print("mContentChanged="); writer.println(mContentChanged);
249     }
250 }
251