CursorLoader.java revision 8a2ca60963f77938e1a611f2342ad043dc9467cf
1/*
2 * Copyright (C) 2011 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.support.v4.content;
18
19import android.content.Context;
20import android.database.ContentObserver;
21import android.database.Cursor;
22import android.net.Uri;
23import android.support.v4.database.CursorHelper;
24
25import java.io.FileDescriptor;
26import java.io.PrintWriter;
27import java.util.Arrays;
28
29/**
30 * Static library support version of the framework's {@link android.content.CursorLoader}.
31 * Used to write apps that run on platforms prior to Android 3.0.  When running
32 * on Android 3.0 or above, this implementation is still used; it does not try
33 * to switch to the framework's implementation.  See the framework SDK
34 * documentation for a class overview.
35 */
36public class CursorLoader extends AsyncTaskLoader<Cursor> {
37    final ForceLoadContentObserver mObserver;
38
39    Uri mUri;
40    String[] mProjection;
41    String mSelection;
42    String[] mSelectionArgs;
43    String mSortOrder;
44
45    Cursor mCursor;
46
47    /* Runs on a worker thread */
48    @Override
49    public Cursor loadInBackground() {
50        Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
51                mSelectionArgs, mSortOrder);
52        if (cursor != null) {
53            // Ensure the cursor window is filled
54            cursor.getCount();
55            registerContentObserver(cursor, mObserver);
56        }
57        return cursor;
58    }
59
60    /**
61     * Registers an observer to get notifications from the content provider
62     * when the cursor needs to be refreshed.
63     */
64    void registerContentObserver(Cursor cursor, ContentObserver observer) {
65        cursor.registerContentObserver(mObserver);
66    }
67
68    /* Runs on the UI thread */
69    @Override
70    public void deliverResult(Cursor cursor) {
71        if (isReset()) {
72            // An async query came in while the loader is stopped
73            if (cursor != null) {
74                CursorHelper.closeAsync(cursor);
75            }
76            return;
77        }
78        Cursor oldCursor = mCursor;
79        mCursor = cursor;
80
81        if (isStarted()) {
82            super.deliverResult(cursor);
83        }
84
85        if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
86            CursorHelper.closeAsync(oldCursor);
87        }
88    }
89
90    /**
91     * Creates an empty unspecified CursorLoader.  You must follow this with
92     * calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc
93     * to specify the query to perform.
94     */
95    public CursorLoader(Context context) {
96        super(context);
97        mObserver = new ForceLoadContentObserver();
98    }
99
100    /**
101     * Creates a fully-specified CursorLoader.  See
102     * {@link ContentResolver#query(Uri, String[], String, String[], String)
103     * ContentResolver.query()} for documentation on the meaning of the
104     * parameters.  These will be passed as-is to that call.
105     */
106    public CursorLoader(Context context, Uri uri, String[] projection, String selection,
107            String[] selectionArgs, String sortOrder) {
108        super(context);
109        mObserver = new ForceLoadContentObserver();
110        mUri = uri;
111        mProjection = projection;
112        mSelection = selection;
113        mSelectionArgs = selectionArgs;
114        mSortOrder = sortOrder;
115    }
116
117    /**
118     * Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
119     * will be called on the UI thread. If a previous load has been completed and is still valid
120     * the result may be passed to the callbacks immediately.
121     *
122     * Must be called from the UI thread
123     */
124    @Override
125    protected void onStartLoading() {
126        if (mCursor != null) {
127            deliverResult(mCursor);
128        }
129        if (takeContentChanged() || mCursor == null) {
130            forceLoad();
131        }
132    }
133
134    /**
135     * Must be called from the UI thread
136     */
137    @Override
138    protected void onStopLoading() {
139        // Attempt to cancel the current load task if possible.
140        cancelLoad();
141    }
142
143    @Override
144    public void onCanceled(Cursor cursor) {
145        if (cursor != null && !cursor.isClosed()) {
146            CursorHelper.closeAsync(cursor);
147        }
148    }
149
150    @Override
151    protected void onReset() {
152        super.onReset();
153
154        // Ensure the loader is stopped
155        onStopLoading();
156
157        if (mCursor != null && !mCursor.isClosed()) {
158            CursorHelper.closeAsync(mCursor);
159        }
160        mCursor = null;
161    }
162
163    public Uri getUri() {
164        return mUri;
165    }
166
167    public void setUri(Uri uri) {
168        mUri = uri;
169    }
170
171    public String[] getProjection() {
172        return mProjection;
173    }
174
175    public void setProjection(String[] projection) {
176        mProjection = projection;
177    }
178
179    public String getSelection() {
180        return mSelection;
181    }
182
183    public void setSelection(String selection) {
184        mSelection = selection;
185    }
186
187    public String[] getSelectionArgs() {
188        return mSelectionArgs;
189    }
190
191    public void setSelectionArgs(String[] selectionArgs) {
192        mSelectionArgs = selectionArgs;
193    }
194
195    public String getSortOrder() {
196        return mSortOrder;
197    }
198
199    public void setSortOrder(String sortOrder) {
200        mSortOrder = sortOrder;
201    }
202
203    @Override
204    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
205        super.dump(prefix, fd, writer, args);
206        writer.print(prefix); writer.print("mUri="); writer.println(mUri);
207        writer.print(prefix); writer.print("mProjection=");
208                writer.println(Arrays.toString(mProjection));
209        writer.print(prefix); writer.print("mSelection="); writer.println(mSelection);
210        writer.print(prefix); writer.print("mSelectionArgs=");
211                writer.println(Arrays.toString(mSelectionArgs));
212        writer.print(prefix); writer.print("mSortOrder="); writer.println(mSortOrder);
213        writer.print(prefix); writer.print("mCursor="); writer.println(mCursor);
214        writer.print(prefix); writer.print("mContentChanged="); writer.println(mContentChanged);
215    }
216}
217