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