/* * 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; /** * 用于将游标列映射到XML文件中定义的文本视图或图像视图的简单适配器. * 你可以指定有哪些列,由那些视图显示这些列的内容,并通过XML定义这些视图的呈现. * * 绑定由两个阶段组成.首先,如果{@link android.widget.SimpleCursorAdapter.ViewBinder} * 可用,则执行 * {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)}. * 如果返回在为真,代表发生了绑定.如果返回值为假,并且要绑定的是文本视图,则执行 * {@link #setViewText(TextView, String)} 方法.如果返回值为假,并且要绑定的是 * ImageView,则执行{@link #setViewImage(ImageView, String)}.如果没有适当的绑定发生, * 将抛出{@link IllegalStateException}. * * 如果该适配器与过滤功能同时使用,比如在 * {@link android.widget.AutoCompleteTextView}中,可以使用 * {@link android.widget.SimpleCursorAdapter.CursorToStringConverter}和 * {@link android.widget.FilterQueryProvider}接口,用于控制过滤过程. * 详细信息可以参考 * {@link #convertToString(android.database.Cursor)}和 * {@link #runQueryOnBackgroundThread(CharSequence)}. */ 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; /** * 构造函数,启用自动再检索功能. * * @deprecated 该选项已经废止,因为他会在应用程序的 UI 线程中执行 * 游标的检索,会导致响应变慢甚至发生应用程序无响应错误. * 请使用带有 {@link android.content.CursorLoader} * 的 {@link android.app.LoaderManager} 来代替. * * @param context 与运行中的 SimpleListItemFactory 关联的 ListView 的上下文 * @param layout 为该列表定义了视图的布局文件标识.布局文件应该至少包括“to”中定义的视图 * @param c 数据库游标.如果游标不可用,可设为空. * @param from 代表要绑定到UI的数据的列名列表.如果游标不可用,可设为空. * @param to 用于显示“from”参数的列的视图.应该都是 TextViews. * 视图与from参数按位置一一对应.如果游标不可用,可设为空. */ @Deprecated public SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { super(context, layout, c); mTo = to; mOriginalFrom = from; findColumns(c, from); } /** * 标准构造函数. * * @param context 与运行中的 SimpleListItemFactory 关联的 ListView 的上下文 * @param layout 为该列表定义了视图的布局文件标识.布局文件应该至少包括“to”中定义的视图 * @param c 数据库游标.如果游标不可用,可设为空. * @param from 代表要绑定到UI的数据的列名列表.如果游标不可用,可设为空. * @param to 用于显示“from”参数的列的视图.应该都是 TextViews. * 视图与from参数按位置一一对应.如果游标不可用,可设为空. * @param flags 用于决定适配器行为的标志位.与 {@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); } /** * 与视图绑定有两个阶段.第一阶段:如果SimpleCursorAdapter.ViewBinder可用,将会调用setViewValue(android.view.View, android.database.Cursor, int)方法.该方法返回true就说明绑定成功,否则返回false ,这就到了第二阶段,SimpleCursorAdapter内部开始自行绑定,过程是这样的,若绑定到TextView上,调用setViewText();若绑定到ImageView上,调用setViewImage();如果视图不是TextView或ImageView则抛出IllegalStateException异常. * 将传入构造函数“to”参数的所有字段名和他们对应的“from”参数的绑定在一起. * * 绑定由两个阶段组成.首先,如果{@link android.widget.SimpleCursorAdapter.ViewBinder} * 可用,则执行 * {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)}. * 如果返回在为真,代表发生了绑定.如果返回值为假,并且要绑定的是文本视图,则执行 * {@link #setViewText(TextView, String)} 方法.如果返回值为假,并且要绑定的是 * ImageView,则执行{@link #setViewImage(ImageView, String)}.如果没有适当的绑定发生, * 将抛出{@link IllegalStateException}. * * @throws IllegalStateException 如果无法绑定. * * @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"); } } } } } /** * 返回用于绑定数据到视图的{@link ViewBinder}. * * @return ViewBinder 或者当绑定器不存在时返回空. * * @see #bindView(android.view.View, android.content.Context, android.database.Cursor) * @see #setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder) */ public ViewBinder getViewBinder() { return mViewBinder; } /** * 设置用于绑定数据到视图的绑定器. * * @param viewBinder 用于将数据绑定到视图的绑定器,若要移除既存绑定器可以设为空. * * @see #bindView(android.view.View, android.content.Context, android.database.Cursor) * @see #getViewBinder() */ public void setViewBinder(ViewBinder viewBinder) { mViewBinder = viewBinder; } /** * 由bindView()调用,当没有既存的 ViewBinder 或者 ViewBinder * 不能处理到ImageView的绑定时,为ImageView设置图像. * * 默认情况,字符串值作为图像资源对待.如果该值不能作为图像资源, * 将其作为图像URI对待. * * 为需要过滤从数据库中取得的字符串的适配器重写而准备的函数. * * @param v 要设置图像的ImageView. * @param value 从游标取得的值. */ public void setViewImage(ImageView v, String value) { try { v.setImageResource(Integer.parseInt(value)); } catch (NumberFormatException nfe) { v.setImageURI(Uri.parse(value)); } } /** * 由bindView()调用,当没有既存的 ViewBinder 或者 ViewBinder * 不能处理到文本视图的绑定时,为文本视图设置文本. * * 为需要过滤从数据库中取得的字符串的适配器重写而准备的函数. * * @param v 要设置文本的文本视图. * @param text 要设置到文本视图中的文本. */ public void setViewText(TextView v, String text) { v.setText(text); } /** * 返回用于取得代表游标的字符串的列索引. * * @return 当前游标的有效的列索引或者-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; } /** * 定义代表游标的字符串的列索引.该列用于在当前 CursorToStringConverter 为空时, * 将游标转换为字符串时使用. * * @param stringConversionColumn 使用默认转换机制时,当前游标的有效的列索引或者-1. * * @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; } /** * 返回用于将过滤游标转换为字符串的转换器. * * @return 如果转换器不存在返回空,否则返回 * {@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; } /** * 设置用于将过滤游标转换为字符串的转换器. * * @param cursorToStringConverter 将游标转为字符串的转换器,要删除时可设为空. * * @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; } /** * 返回由当前 CursorToStringConverter 指定的代表游标的 CharSequence. * 如果没有指定 CursorToStringConverter,则用字符串转换列代表. * 如果转换列为 -1,对于空游标返回空字符串,其他返回 Cursor.toString(). * * @param cursor 转换为 CharSequence 的游标. * * @return 代表游标的非空 CharSequence. */ @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); } /** * 同时改变游标及绑定到视图的游标列. * * @param c 数据库游标.如果游标不存在可以为空. * @param from 代表要绑定到UI的数据的列名列表.如果游标不存在可以为空. * @param to 用于显示“from”参数中数据的视图.应该都是文本视图. * 视图的位置与数据的位置一一对应.如果游标不存在可以为空. */ 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); } /** * 该接口可用于 SimpleCursorAdapter 的外部客户端将游标绑定到视图. * * 对于 SimpleCursorAdapter 不直接支持或要改变 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 { /** * 绑定指定位置的游标列到指定视图. * * 若该 ViewBinder 处理了绑定,该方法应该返回真.若该方法返回假, * SimpleCursorAdapter 将尝试去执行绑定操作. * * @param view 要绑定数据的视图. * @param cursor 用于取得数据的游标. * @param columnIndex 要取得数据对应的游标中的列. * * @return 若数据已绑定到视图返回真,否则返回假. */ boolean setViewValue(View view, Cursor cursor, int columnIndex); } /** * 该接口允许 SimpleCursorAdapter 的外部客户端定义游标如何转换为字符串. * * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) */ public static interface CursorToStringConverter { /** * 返回代表指定游标的CharSequence. * * @param cursor 要求返回 CharSequence 的游标. * * @return 代表指定游标的非空 CharSequence. */ CharSequence convertToString(Cursor cursor); } }