| /* |
| * 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.Cursor; |
| import android.net.Uri; |
| import android.view.View; |
| |
| /** |
| * An easy adapter to map columns from a cursor to TextViews or ImageViews |
| * defined in an XML file. You can specify which columns you want, which |
| * views you want to display the columns, and the XML file that defines |
| * the appearance of these views. |
| * |
| * Binding occurs in two phases. First, if a |
| * {@link android.widget.SimpleCursorAdapter.ViewBinder} is available, |
| * {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)} |
| * is invoked. If the returned value is true, binding has occured. If the |
| * returned value is false and the view to bind is a TextView, |
| * {@link #setViewText(TextView, String)} is invoked. If the returned value |
| * is false and the view to bind is an ImageView, |
| * {@link #setViewImage(ImageView, String)} is invoked. If no appropriate |
| * binding can be found, an {@link IllegalStateException} is thrown. |
| * |
| * If this adapter is used with filtering, for instance in an |
| * {@link android.widget.AutoCompleteTextView}, you can use the |
| * {@link android.widget.SimpleCursorAdapter.CursorToStringConverter} and the |
| * {@link android.widget.FilterQueryProvider} interfaces |
| * to get control over the filtering process. You can refer to |
| * {@link #convertToString(android.database.Cursor)} and |
| * {@link #runQueryOnBackgroundThread(CharSequence)} for more information. |
| */ |
| public class SimpleCursorAdapter extends ResourceCursorAdapter { |
| /** |
| * A list of columns containing the data to bind to the UI. |
| * This field should be made private, so it is hidden from the SDK. |
| * {@hide} |
| */ |
| protected int[] mFrom; |
| /** |
| * A list of View ids representing the views to which the data must be bound. |
| * This field should be made private, so it is hidden from the SDK. |
| * {@hide} |
| */ |
| protected int[] mTo; |
| |
| private int mStringConversionColumn = -1; |
| private CursorToStringConverter mCursorToStringConverter; |
| private ViewBinder mViewBinder; |
| |
| String[] mOriginalFrom; |
| |
| /** |
| * Constructor the enables auto-requery. |
| * |
| * @deprecated This option is discouraged, as it results in Cursor queries |
| * being performed on the application's UI thread and thus can cause poor |
| * responsiveness or even Application Not Responding errors. As an alternative, |
| * use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}. |
| */ |
| @Deprecated |
| public SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { |
| super(context, layout, c); |
| mTo = to; |
| mOriginalFrom = from; |
| findColumns(c, from); |
| } |
| |
| /** |
| * Standard constructor. |
| * |
| * @param context The context where the ListView associated with this |
| * SimpleListItemFactory is running |
| * @param layout resource identifier of a layout file that defines the views |
| * for this list item. The layout file should include at least |
| * those named views defined in "to" |
| * @param c The database cursor. Can be null if the cursor is not available yet. |
| * @param from A list of column names representing the data to bind to the UI. Can be null |
| * if the cursor is not available yet. |
| * @param to The views that should display column in the "from" parameter. |
| * These should all be TextViews. The first N views in this list |
| * are given the values of the first N columns in the from |
| * parameter. Can be null if the cursor is not available yet. |
| * @param flags Flags used to determine the behavior of the adapter, |
| * as per {@link CursorAdapter#CursorAdapter(Context, Cursor, int)}. |
| */ |
| public SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, |
| int[] to, int flags) { |
| super(context, layout, c, flags); |
| mTo = to; |
| mOriginalFrom = from; |
| findColumns(c, from); |
| } |
| |
| /** |
| * Binds all of the field names passed into the "to" parameter of the |
| * constructor with their corresponding cursor columns as specified in the |
| * "from" parameter. |
| * |
| * Binding occurs in two phases. First, if a |
| * {@link android.widget.SimpleCursorAdapter.ViewBinder} is available, |
| * {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)} |
| * is invoked. If the returned value is true, binding has occured. If the |
| * returned value is false and the view to bind is a TextView, |
| * {@link #setViewText(TextView, String)} is invoked. If the returned value is |
| * false and the view to bind is an ImageView, |
| * {@link #setViewImage(ImageView, String)} is invoked. If no appropriate |
| * binding can be found, an {@link IllegalStateException} is thrown. |
| * |
| * @throws IllegalStateException if binding cannot occur |
| * |
| * @see android.widget.CursorAdapter#bindView(android.view.View, |
| * android.content.Context, android.database.Cursor) |
| * @see #getViewBinder() |
| * @see #setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder) |
| * @see #setViewImage(ImageView, String) |
| * @see #setViewText(TextView, String) |
| */ |
| @Override |
| public void bindView(View view, Context context, Cursor cursor) { |
| final ViewBinder binder = mViewBinder; |
| final int count = mTo.length; |
| final int[] from = mFrom; |
| final int[] to = mTo; |
| |
| for (int i = 0; i < count; i++) { |
| final View v = view.findViewById(to[i]); |
| if (v != null) { |
| boolean bound = false; |
| if (binder != null) { |
| bound = binder.setViewValue(v, cursor, from[i]); |
| } |
| |
| if (!bound) { |
| String text = cursor.getString(from[i]); |
| if (text == null) { |
| text = ""; |
| } |
| |
| if (v instanceof TextView) { |
| setViewText((TextView) v, text); |
| } else if (v instanceof ImageView) { |
| setViewImage((ImageView) v, text); |
| } else { |
| throw new IllegalStateException(v.getClass().getName() + " is not a " + |
| " view that can be bounds by this SimpleCursorAdapter"); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns the {@link ViewBinder} used to bind data to views. |
| * |
| * @return a ViewBinder or null if the binder does not exist |
| * |
| * @see #bindView(android.view.View, android.content.Context, android.database.Cursor) |
| * @see #setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder) |
| */ |
| public ViewBinder getViewBinder() { |
| return mViewBinder; |
| } |
| |
| /** |
| * Sets the binder used to bind data to views. |
| * |
| * @param viewBinder the binder used to bind data to views, can be null to |
| * remove the existing binder |
| * |
| * @see #bindView(android.view.View, android.content.Context, android.database.Cursor) |
| * @see #getViewBinder() |
| */ |
| public void setViewBinder(ViewBinder viewBinder) { |
| mViewBinder = viewBinder; |
| } |
| |
| /** |
| * Called by bindView() to set the image for an ImageView but only if |
| * there is no existing ViewBinder or if the existing ViewBinder cannot |
| * handle binding to an ImageView. |
| * |
| * By default, the value will be treated as an image resource. If the |
| * value cannot be used as an image resource, the value is used as an |
| * image Uri. |
| * |
| * Intended to be overridden by Adapters that need to filter strings |
| * retrieved from the database. |
| * |
| * @param v ImageView to receive an image |
| * @param value the value retrieved from the cursor |
| */ |
| public void setViewImage(ImageView v, String value) { |
| try { |
| v.setImageResource(Integer.parseInt(value)); |
| } catch (NumberFormatException nfe) { |
| v.setImageURI(Uri.parse(value)); |
| } |
| } |
| |
| /** |
| * Called by bindView() to set the text for a TextView but only if |
| * there is no existing ViewBinder or if the existing ViewBinder cannot |
| * handle binding to a TextView. |
| * |
| * Intended to be overridden by Adapters that need to filter strings |
| * retrieved from the database. |
| * |
| * @param v TextView to receive text |
| * @param text the text to be set for the TextView |
| */ |
| public void setViewText(TextView v, String text) { |
| v.setText(text); |
| } |
| |
| /** |
| * Return the index of the column used to get a String representation |
| * of the Cursor. |
| * |
| * @return a valid index in the current Cursor or -1 |
| * |
| * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) |
| * @see #setStringConversionColumn(int) |
| * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) |
| * @see #getCursorToStringConverter() |
| */ |
| public int getStringConversionColumn() { |
| return mStringConversionColumn; |
| } |
| |
| /** |
| * Defines the index of the column in the Cursor used to get a String |
| * representation of that Cursor. The column is used to convert the |
| * Cursor to a String only when the current CursorToStringConverter |
| * is null. |
| * |
| * @param stringConversionColumn a valid index in the current Cursor or -1 to use the default |
| * conversion mechanism |
| * |
| * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) |
| * @see #getStringConversionColumn() |
| * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) |
| * @see #getCursorToStringConverter() |
| */ |
| public void setStringConversionColumn(int stringConversionColumn) { |
| mStringConversionColumn = stringConversionColumn; |
| } |
| |
| /** |
| * Returns the converter used to convert the filtering Cursor |
| * into a String. |
| * |
| * @return null if the converter does not exist or an instance of |
| * {@link android.widget.SimpleCursorAdapter.CursorToStringConverter} |
| * |
| * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) |
| * @see #getStringConversionColumn() |
| * @see #setStringConversionColumn(int) |
| * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) |
| */ |
| public CursorToStringConverter getCursorToStringConverter() { |
| return mCursorToStringConverter; |
| } |
| |
| /** |
| * Sets the converter used to convert the filtering Cursor |
| * into a String. |
| * |
| * @param cursorToStringConverter the Cursor to String converter, or |
| * null to remove the converter |
| * |
| * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) |
| * @see #getStringConversionColumn() |
| * @see #setStringConversionColumn(int) |
| * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) |
| */ |
| public void setCursorToStringConverter(CursorToStringConverter cursorToStringConverter) { |
| mCursorToStringConverter = cursorToStringConverter; |
| } |
| |
| /** |
| * Returns a CharSequence representation of the specified Cursor as defined |
| * by the current CursorToStringConverter. If no CursorToStringConverter |
| * has been set, the String conversion column is used instead. If the |
| * conversion column is -1, the returned String is empty if the cursor |
| * is null or Cursor.toString(). |
| * |
| * @param cursor the Cursor to convert to a CharSequence |
| * |
| * @return a non-null CharSequence representing the cursor |
| */ |
| @Override |
| public CharSequence convertToString(Cursor cursor) { |
| if (mCursorToStringConverter != null) { |
| return mCursorToStringConverter.convertToString(cursor); |
| } else if (mStringConversionColumn > -1) { |
| return cursor.getString(mStringConversionColumn); |
| } |
| |
| return super.convertToString(cursor); |
| } |
| |
| /** |
| * Create a map from an array of strings to an array of column-id integers in cursor c. |
| * If c is null, the array will be discarded. |
| * |
| * @param c the cursor to find the columns from |
| * @param from the Strings naming the columns of interest |
| */ |
| private void findColumns(Cursor c, String[] from) { |
| if (c != null) { |
| int i; |
| int count = from.length; |
| if (mFrom == null || mFrom.length != count) { |
| mFrom = new int[count]; |
| } |
| for (i = 0; i < count; i++) { |
| mFrom[i] = c.getColumnIndexOrThrow(from[i]); |
| } |
| } else { |
| mFrom = null; |
| } |
| } |
| |
| @Override |
| public Cursor swapCursor(Cursor c) { |
| // super.swapCursor() will notify observers before we have |
| // a valid mapping, make sure we have a mapping before this |
| // happens |
| findColumns(c, mOriginalFrom); |
| return super.swapCursor(c); |
| } |
| |
| /** |
| * Change the cursor and change the column-to-view mappings at the same time. |
| * |
| * @param c The database cursor. Can be null if the cursor is not available yet. |
| * @param from A list of column names representing the data to bind to the UI. Can be null |
| * if the cursor is not available yet. |
| * @param to The views that should display column in the "from" parameter. |
| * These should all be TextViews. The first N views in this list |
| * are given the values of the first N columns in the from |
| * parameter. Can be null if the cursor is not available yet. |
| */ |
| public void changeCursorAndColumns(Cursor c, String[] from, int[] to) { |
| mOriginalFrom = from; |
| mTo = to; |
| // super.changeCursor() will notify observers before we have |
| // a valid mapping, make sure we have a mapping before this |
| // happens |
| findColumns(c, mOriginalFrom); |
| super.changeCursor(c); |
| } |
| |
| /** |
| * This class can be used by external clients of SimpleCursorAdapter |
| * to bind values fom the Cursor to views. |
| * |
| * You should use this class to bind values from the Cursor to views |
| * that are not directly supported by SimpleCursorAdapter or to |
| * change the way binding occurs for views supported by |
| * SimpleCursorAdapter. |
| * |
| * @see SimpleCursorAdapter#bindView(android.view.View, android.content.Context, android.database.Cursor) |
| * @see SimpleCursorAdapter#setViewImage(ImageView, String) |
| * @see SimpleCursorAdapter#setViewText(TextView, String) |
| */ |
| public static interface ViewBinder { |
| /** |
| * Binds the Cursor column defined by the specified index to the specified view. |
| * |
| * When binding is handled by this ViewBinder, this method must return true. |
| * If this method returns false, SimpleCursorAdapter will attempts to handle |
| * the binding on its own. |
| * |
| * @param view the view to bind the data to |
| * @param cursor the cursor to get the data from |
| * @param columnIndex the column at which the data can be found in the cursor |
| * |
| * @return true if the data was bound to the view, false otherwise |
| */ |
| boolean setViewValue(View view, Cursor cursor, int columnIndex); |
| } |
| |
| /** |
| * This class can be used by external clients of SimpleCursorAdapter |
| * to define how the Cursor should be converted to a String. |
| * |
| * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) |
| */ |
| public static interface CursorToStringConverter { |
| /** |
| * Returns a CharSequence representing the specified Cursor. |
| * |
| * @param cursor the cursor for which a CharSequence representation |
| * is requested |
| * |
| * @return a non-null CharSequence representing the cursor |
| */ |
| CharSequence convertToString(Cursor cursor); |
| } |
| |
| } |