private@NonNullView createViewFromResource(@NonNull LayoutInflater inflater, int position, @Nullable View convertView, @NonNull ViewGroup parent, int resource){ final View view; final TextView text;
try { if (mFieldId == 0) { // If no custom field is assigned, assume the whole resource is a TextView // 不指定 TextView id,则默认整个布局文件就是 TextView text = (TextView) view; } else { // Otherwise, find the TextView field within the layout // 至少包含一个 TextView text = (TextView) view.findViewById(mFieldId);
if (text == null) { thrownew RuntimeException("Failed to find view with ID " + mContext.getResources().getResourceName(mFieldId) + " in item layout"); } } } catch (ClassCastException e) { Log.e("ArrayAdapter", "You must supply a resource ID for a TextView"); thrownew IllegalStateException( "ArrayAdapter requires the resource ID to be a TextView", e); }
// getItem 的实现是从 objects 中获取数据 final T item = getItem(position); if (item instanceof CharSequence) { text.setText((CharSequence) item); } else { // 数据转换为字符串。T 可以是简单数据类型,也可以是自定义的类 text.setText(item.toString()); }
public String toString(){ return mStr + String.valueOf(mNum); } } // 初始化数据集合 private List<UserData> initUserDataList(){ List<UserData> dataList = new ArrayList<UserData>(); String pre = "Right"; for(int i = 1; i <= 4; i++) { UserData data = new UserData(pre, i); dataList.add(data); } return dataList; }
如上代码对应的效果图:
SimpleCursorAdapter 介绍
类定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// 类定义 publicclassSimpleCursorAdapterextendsResourceCursorAdapter{...} publicabstractclassResourceCursorAdapterextendsCursorAdapter{...} /** * Adapter that exposes data from a {@link android.database.Cursor Cursor} to a * {@link android.widget.ListView ListView} widget. * <p> * The Cursor must include a column named "_id" or this class will not work. * Additionally, using {@link android.database.MergeCursor} with this class will * not work if the merged Cursors have overlapping values in their "_id" * columns. */ publicabstractclassCursorAdapterextendsBaseAdapterimplementsFilterable, CursorFilter.CursorFilterClient, ThemedSpinnerAdapter{...}
// 构造函数 publicSimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags){...}
// 如果 projections 中不包含 id, 在使用 swapCursor 时会抛出如下异常 06-3011:15:26.67911899-11899/com.***.*** E/AndroidRuntime: FATAL EXCEPTION: main Process: com.***.***, PID: 11899 java.lang.IllegalArgumentException: column '_id' does not exist at android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.java:303) at android.database.CursorWrapper.getColumnIndexOrThrow(CursorWrapper.java:78) at android.widget.CursorAdapter.swapCursor(CursorAdapter.java:342) at android.widget.SimpleCursorAdapter.swapCursor(SimpleCursorAdapter.java:346)
// SimpleAdapter.java:: bindview,代码部分有删减 privatevoidbindView(int position, View view){ ... final ViewBinder binder = mViewBinder; final String[] from = mFrom; finalint[] to = mTo; ... boolean bound = false; // 使用了系统默认不支持的控件,需要实现 ViewBinder // 重写 setViewValue if (binder != null) { bound = binder.setViewValue(v, data, text); } // 系统默认支持的控件:Checkable,TextView,ImageView // 如果 binder 不存在或者绑定不成功,使用系统默认方式绑定 if (!bound) { if (v instanceof Checkable) { if (data instanceof Boolean) { ((Checkable) v).setChecked((Boolean) data); } elseif (v instanceof TextView) { // Note: keep the instanceof TextView check at the bottom of these // ifs since a lot of views are TextViews (e.g. CheckBoxes). setViewText((TextView) v, text); } else { thrownew IllegalStateException(v.getClass().getName() + " should be bound to a Boolean, not a " + (data == null ? "<unknown type>" : data.getClass())); } } elseif (v instanceof TextView) { // Note: keep the instanceof TextView check at the bottom of these // ifs since a lot of views are TextViews (e.g. CheckBoxes). setViewText((TextView) v, text); } elseif (v instanceof ImageView) { if (data instanceof Integer) { setViewImage((ImageView) v, (Integer) data); } else { setViewImage((ImageView) v, text); } } else { thrownew IllegalStateException(v.getClass().getName() + " is not a " + " view that can be bounds by this SimpleAdapter"); } } ... }
ImageView 期望绑定值是一个资源 id 或者一个字符串,通过调用 setViewImage(ImageView, int) 或 setViewImage(ImageView, String) 绑定数据
如果没有一个合适的绑定发生将会抛出 IllegalStateException
自定义布局
自定义布局中如果包含了不是系统默认支持控件,需要实现 ViewBinder 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
publicstaticinterfaceViewBinder{ /** * Binds the specified data to the specified view. * * When binding is handled by this ViewBinder, this method must return true. * If this method returns false, SimpleAdapter will attempts to handle * the binding on its own. * * @param view the view to bind the data to * @param data the data to bind to the view * @param textRepresentation a safe String representation of the supplied data: * it is either the result of data.toString() or an empty String but it * is never null * * @return true if the data was bound to the view, false otherwise */ booleansetViewValue(View view, Object data, String textRepresentation); }
BaseAdapter 介绍
类定义及重写
类定义: public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {...}
重写四个方法:
1 2 3 4
publicintgetCount(){...} public Object getItem(int position){...} publiclonggetItemId(int position){...} public View getView(int position, View convertView, ViewGroup parent){...}
To work efficiently the adapter implemented here uses two techniques: (译:提升 Adapter 性能的两种方法:) -It reuses the convertView passed to getView() to avoid inflating View when it is not necessary (译:重用缓存 convertView 传递给 getView() 方法来避免填充不必要的视图) -It uses the ViewHolder pattern to avoid calling findViewById() when it is not necessary (译:使用 ViewHolder 模式来避免没有必要的调用 findViewById():因为太多的 findViewById 也会影响性能) ViewHolder类的作用 -The ViewHolder pattern consists in storing a data structure in the tag of the view returned by getView().This data structures contains references to the views we want to bind data to, thus avoiding calling to findViewById() every time getView() is invoked (译:ViewHolder 模式通过 getView() 方法返回的视图的标签 Tag 中存储一个数据结构,这个数据结构包含了指向我们要绑定数据的视图的引用,从而避免每次调用 getView() 的时候调用 findViewById())