summaryrefslogtreecommitdiffstats
path: root/core/java/android/widget/CursorAdapter.java
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch)
tree35051494d2af230dce54d6b31c6af8fc24091316 /core/java/android/widget/CursorAdapter.java
downloadframeworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.zip
frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.gz
frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.bz2
Initial Contribution
Diffstat (limited to 'core/java/android/widget/CursorAdapter.java')
-rw-r--r--core/java/android/widget/CursorAdapter.java382
1 files changed, 382 insertions, 0 deletions
diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java
new file mode 100644
index 0000000..cacaeab
--- /dev/null
+++ b/core/java/android/widget/CursorAdapter.java
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.DataSetObserver;
+import android.os.Handler;
+import android.util.Config;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Adapter that exposes data from a {@link android.database.Cursor Cursor} to a
+ * {@link android.widget.ListView ListView} widget. The Cursor must include
+ * a column named "_id" or this class will not work.
+ */
+public abstract class CursorAdapter extends BaseAdapter implements Filterable,
+ CursorFilter.CursorFilterClient {
+ /**
+ * This field should be made private, so it is hidden from the SDK.
+ * {@hide}
+ */
+ protected boolean mDataValid;
+ /**
+ * This field should be made private, so it is hidden from the SDK.
+ * {@hide}
+ */
+ protected boolean mAutoRequery;
+ /**
+ * This field should be made private, so it is hidden from the SDK.
+ * {@hide}
+ */
+ protected Cursor mCursor;
+ /**
+ * This field should be made private, so it is hidden from the SDK.
+ * {@hide}
+ */
+ protected Context mContext;
+ /**
+ * This field should be made private, so it is hidden from the SDK.
+ * {@hide}
+ */
+ protected int mRowIDColumn;
+ /**
+ * This field should be made private, so it is hidden from the SDK.
+ * {@hide}
+ */
+ protected ChangeObserver mChangeObserver;
+ /**
+ * This field should be made private, so it is hidden from the SDK.
+ * {@hide}
+ */
+ protected DataSetObserver mDataSetObserver = new MyDataSetObserver();
+ /**
+ * This field should be made private, so it is hidden from the SDK.
+ * {@hide}
+ */
+ protected CursorFilter mCursorFilter;
+ /**
+ * This field should be made private, so it is hidden from the SDK.
+ * {@hide}
+ */
+ protected FilterQueryProvider mFilterQueryProvider;
+
+ /**
+ * Constructor. The adapter will call requery() on the cursor whenever
+ * it changes so that the most recent data is always displayed.
+ *
+ * @param c The cursor from which to get the data.
+ * @param context The context
+ */
+ public CursorAdapter(Context context, Cursor c) {
+ init(context, c, true);
+ }
+
+ /**
+ * Constructor
+ * @param c The cursor from which to get the data.
+ * @param context The context
+ * @param autoRequery If true the adapter will call requery() on the
+ * cursor whenever it changes so the most recent
+ * data is always displayed.
+ */
+ public CursorAdapter(Context context, Cursor c, boolean autoRequery) {
+ init(context, c, autoRequery);
+ }
+
+ protected void init(Context context, Cursor c, boolean autoRequery) {
+ boolean cursorPresent = c != null;
+ mAutoRequery = autoRequery;
+ mCursor = c;
+ mDataValid = cursorPresent;
+ mContext = context;
+ mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1;
+ mChangeObserver = new ChangeObserver();
+ if (cursorPresent) {
+ c.registerContentObserver(mChangeObserver);
+ c.registerDataSetObserver(mDataSetObserver);
+ }
+ }
+
+ /**
+ * Returns the cursor.
+ * @return the cursor.
+ */
+ public Cursor getCursor() {
+ return mCursor;
+ }
+
+ /**
+ * @see android.widget.ListAdapter#getCount()
+ */
+ public final int getCount() {
+ if (mDataValid && mCursor != null) {
+ return mCursor.getCount();
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * @see android.widget.ListAdapter#getItem(int)
+ */
+ public final Object getItem(int position) {
+ if (mDataValid && mCursor != null) {
+ mCursor.moveToPosition(position);
+ return mCursor;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @see android.widget.ListAdapter#getItemId(int)
+ */
+ public final long getItemId(int position) {
+ if (mDataValid && mCursor != null) {
+ if (mCursor.moveToPosition(position)) {
+ return mCursor.getLong(mRowIDColumn);
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ /**
+ * @see android.widget.ListAdapter#getView(int, View, ViewGroup)
+ */
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (!mDataValid) {
+ throw new IllegalStateException("this should only be called when the cursor is valid");
+ }
+ if (!mCursor.moveToPosition(position)) {
+ throw new IllegalStateException("couldn't move cursor to position " + position);
+ }
+ View v;
+ if (convertView == null) {
+ v = newView(mContext, mCursor, parent);
+ } else {
+ v = convertView;
+ }
+ bindView(v, mContext, mCursor);
+ return v;
+ }
+
+ @Override
+ public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ if (mDataValid) {
+ mCursor.moveToPosition(position);
+ View v;
+ if (convertView == null) {
+ v = newDropDownView(mContext, mCursor, parent);
+ } else {
+ v = convertView;
+ }
+ bindView(v, mContext, mCursor);
+ return v;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Makes a new view to hold the data pointed to by cursor.
+ * @param context Interface to application's global information
+ * @param cursor The cursor from which to get the data. The cursor is already
+ * moved to the correct position.
+ * @param parent The parent to which the new view is attached to
+ * @return the newly created view.
+ */
+ public abstract View newView(Context context, Cursor cursor, ViewGroup parent);
+
+ /**
+ * Makes a new drop down view to hold the data pointed to by cursor.
+ * @param context Interface to application's global information
+ * @param cursor The cursor from which to get the data. The cursor is already
+ * moved to the correct position.
+ * @param parent The parent to which the new view is attached to
+ * @return the newly created view.
+ */
+ public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) {
+ return newView(context, cursor, parent);
+ }
+
+ /**
+ * Bind an existing view to the data pointed to by cursor
+ * @param view Existing view, returned earlier by newView
+ * @param context Interface to application's global information
+ * @param cursor The cursor from which to get the data. The cursor is already
+ * moved to the correct position.
+ */
+ public abstract void bindView(View view, Context context, Cursor cursor);
+
+ /**
+ * Change the underlying cursor to a new cursor. If there is an existing cursor it will be
+ * closed.
+ *
+ * @param cursor the new cursor to be used
+ */
+ public void changeCursor(Cursor cursor) {
+ if (mCursor != null) {
+ mCursor.unregisterContentObserver(mChangeObserver);
+ mCursor.unregisterDataSetObserver(mDataSetObserver);
+ mCursor.close();
+ }
+ mCursor = cursor;
+ if (cursor != null) {
+ cursor.registerContentObserver(mChangeObserver);
+ cursor.registerDataSetObserver(mDataSetObserver);
+ mRowIDColumn = cursor.getColumnIndexOrThrow("_id");
+ mDataValid = true;
+ // notify the observers about the new cursor
+ notifyDataSetChanged();
+ } else {
+ mRowIDColumn = -1;
+ mDataValid = false;
+ // notify the observers about the lack of a data set
+ notifyDataSetInvalidated();
+ }
+ }
+
+ /**
+ * <p>Converts the cursor into a CharSequence. Subclasses should override this
+ * method to convert their results. The default implementation returns an
+ * empty String for null values or the default String representation of
+ * the value.</p>
+ *
+ * @param cursor the cursor to convert to a CharSequence
+ * @return a CharSequence representing the value
+ */
+ public CharSequence convertToString(Cursor cursor) {
+ return cursor == null ? "" : cursor.toString();
+ }
+
+ /**
+ * Runs a query with the specified constraint. This query is requested
+ * by the filter attached to this adapter.
+ *
+ * The query is provided by a
+ * {@link android.widget.FilterQueryProvider}.
+ * If no provider is specified, the current cursor is not filtered and returned.
+ *
+ * After this method returns the resulting cursor is passed to {@link #changeCursor(Cursor)}
+ * and the previous cursor is closed.
+ *
+ * This method is always executed on a background thread, not on the
+ * application's main thread (or UI thread.)
+ *
+ * Contract: when constraint is null or empty, the original results,
+ * prior to any filtering, must be returned.
+ *
+ * @param constraint the constraint with which the query must be filtered
+ *
+ * @return a Cursor representing the results of the new query
+ *
+ * @see #getFilter()
+ * @see #getFilterQueryProvider()
+ * @see #setFilterQueryProvider(android.widget.FilterQueryProvider)
+ */
+ public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
+ if (mFilterQueryProvider != null) {
+ return mFilterQueryProvider.runQuery(constraint);
+ }
+
+ return mCursor;
+ }
+
+ public Filter getFilter() {
+ if (mCursorFilter == null) {
+ mCursorFilter = new CursorFilter(this);
+ }
+ return mCursorFilter;
+ }
+
+ /**
+ * Returns the query filter provider used for filtering. When the
+ * provider is null, no filtering occurs.
+ *
+ * @return the current filter query provider or null if it does not exist
+ *
+ * @see #setFilterQueryProvider(android.widget.FilterQueryProvider)
+ * @see #runQueryOnBackgroundThread(CharSequence)
+ */
+ public FilterQueryProvider getFilterQueryProvider() {
+ return mFilterQueryProvider;
+ }
+
+ /**
+ * Sets the query filter provider used to filter the current Cursor.
+ * The provider's
+ * {@link android.widget.FilterQueryProvider#runQuery(CharSequence)}
+ * method is invoked when filtering is requested by a client of
+ * this adapter.
+ *
+ * @param filterQueryProvider the filter query provider or null to remove it
+ *
+ * @see #getFilterQueryProvider()
+ * @see #runQueryOnBackgroundThread(CharSequence)
+ */
+ public void setFilterQueryProvider(FilterQueryProvider filterQueryProvider) {
+ mFilterQueryProvider = filterQueryProvider;
+ }
+
+ private class ChangeObserver extends ContentObserver {
+ public ChangeObserver() {
+ super(new Handler());
+ }
+
+ @Override
+ public boolean deliverSelfNotifications() {
+ return true;
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ if (mAutoRequery && mCursor != null) {
+ if (Config.LOGV) Log.v("Cursor", "Auto requerying " + mCursor +
+ " due to update");
+ mDataValid = mCursor.requery();
+ }
+ }
+ }
+
+ private class MyDataSetObserver extends DataSetObserver {
+ @Override
+ public void onChanged() {
+ mDataValid = true;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public void onInvalidated() {
+ mDataValid = false;
+ notifyDataSetInvalidated();
+ }
+ }
+
+}