• Android -- Adapter


    体系

    • public interface Adapter----0层(表示继承体系中的层次)
    • public interface ExpandableListAdapter---(无所谓层次因为没有其他接口继承实现它) 这是adapter的始祖,其他个性化的adapter均实现它并加入自己的接口。
      • public interface ListAdapter----1层
      • public interface SpinnerAdapter----1层
        • public interface WrapperListAdapter----2层(实现ListAdapter)
        • public abstract class BaseAdapter----2层(实现了ListAdapter和SpinnerAdapter) 以抽象类的形式出现构造了类型态下的顶层抽象,包容了List和Spinner
          • public class ArrayAdapter----3层
          • public class SimpleAdapter---3层
          • public class CursorAdapter----3层(CursorAdapter其后还有子类这里先不探讨)

    作用

    Adapter是AdapterView视图与数据之间的桥梁,Adapter提供对数据的访问,也负责为每一项数据产生一个对应的View。

    Adapter

    public interface Adapter { 
        //注册一个Observer,当Adapter所表示的数据改变时会通知它,DataSetObserver是一个抽象类,定义了两个方法:onChanged与onInvalidated 
        void registerDataSetObserver(DataSetObserver observer); 
        //取消注册一个Observer 
        void unregisterDataSetObserver(DataSetObserver observer); 
        //所表示的数据的项数 
        int getCount(); 
        //返回指定位置的数据项 
        Object getItem(int position); 
        //返回指定位置的数据项的ID 
        long getItemId(int position); 
        //表示所有数据项的ID是否是稳定的,在BaseAdapter中默认返回了false,假设是不稳定的,在CursorAdapter中返回了true,Cursor中的_ID是不变的 
        boolean hasStableIds(); 
        //为每一个数据项产生相应的视图 
        View getView(int position, View convertView, ViewGroup parent); 
        //为了避免产生大量的View浪费内存,在Android中,AdapterView中的View是可回收的使用的。比如你有100项数据要显示,而你的屏幕一次只能显示10条数据,则 
        //只产生10个View,当往下拖动要显示第11个View时,会把第1个View的引用传递过去,更新里面的数据再显示,也就是说View可重用,只是更新视图中的数据用于显示新 
        //的一项,如果一个视图的视图类型是IGNORE_ITEM_VIEW_TYPE的话,则此视图不会被重用 
        static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE; 
        //获得相应位置的这图类型 
        int getItemViewType(int position); 
        //getView可以返回的View的类型数量。(在HeaderViewListAdapter中可以包含Header和Footer,getView可以返回Header、Footer及Adapter 
        //中的视图,但其getViewTypeCount的实现只是调用了内部Adapter的的getViewTypeCount,忽略了Header、Footer中的View Type,不懂。 
        int getViewTypeCount(); 
        static final int NO_SELECTION = Integer.MIN_VALUE; 
        boolean isEmpty(); 
    }
    
    

    Adapter有两个子接口,ListAdapter(列表)与SpinnerAdapter(下拉列表),它们都只定义了少数方法。一般除WrapperListAdapter接口及其实现类只实现了ListAdapter外,都同时实现了这两个接口。

    ListAdapter

    //是否在ListAdapter中的所有项都enabled,即是否所有项都selectable和clickable 
    public boolean areAllItemsEnabled(); 
    //指定位置的项是否是enabled的 
    boolean isEnabled(int position);
    

    SpinnerAdapter

    //产生相应位置下拉项的视图 
    public View getDropDownView(int position, View convertView, ViewGroup parent);
    

    BaseAdapter

    一个抽象类,Adapter的基础实现类,一般作为其他实现类的基类,同时实现ListAdapter与SpinnerAdapter,提供了一些方法的默认实现:

    public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { 
        //提供一些方法,当数据改变时调用注册的DataSetObserver的回调函数 
        private final DataSetObservable mDataSetObservable = new DataSetObservable(); 
        public boolean hasStableIds() { 
            return false; 
        } 
        public void registerDataSetObserver(DataSetObserver observer) { 
            mDataSetObservable.registerObserver(observer); 
        } 
        public void unregisterDataSetObserver(DataSetObserver observer) { 
            mDataSetObservable.unregisterObserver(observer); 
        } 
        //通知相关联的视图,相应的数据已经改变 
        public void notifyDataSetChanged() { 
            mDataSetObservable.notifyChanged(); 
        } 
        public void notifyDataSetInvalidated() { 
            mDataSetObservable.notifyInvalidated(); 
        } 
        public boolean areAllItemsEnabled() { 
            return true; 
        } 
        public boolean isEnabled(int position) { 
            return true; 
        } 
        //通过getView实现 
        public View getDropDownView(int position, View convertView, ViewGroup parent) { 
            return getView(position, convertView, parent); 
        } 
        public int getItemViewType(int position) { 
            return 0; 
        } 
        public int getViewTypeCount() { 
            return 1; 
        } 
        public boolean isEmpty() { 
            return getCount() == 0; 
        } 
    }
    

    ArrayAdapter

    private void init(Context context, int resource, int textViewResourceId, List<T> objects) { 
           mContext = context; 
           mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
           mResource = mDropDownResource = resource; 
           mObjects = objects; 
           mFieldId = textViewResourceId; 
       }
    

    类中有两个域保存数据:

    private ArrayList<T> mOriginalValues; 
    private List<T> mObjects;
    

    其中mOriginalValues用于过滤数据时保存过滤前的数据,将过滤后的数据存入mObjects。

    在ArrayAdapter中还定义了add,insert,remove,clear函数用于改变数据,并定义了一个布尔变量mNotifyChange用于表示用这些函数改变数据后是否通知视图(调用notifyDataSetChanged,调用这个函数时会把mNotifyChange置为true。

    一些函数的实现:

    public int getCount() { 
        return mObjects.size(); 
    } 
    public T getItem(int position) { 
        return mObjects.get(position); 
    } 
    public int getPosition(T item) { 
        return mObjects.indexOf(item); 
    } 
    public long getItemId(int position) { 
        return position; 
    } 
    public View getView(int position, View convertView, ViewGroup parent) { 
        return createViewFromResource(position, convertView, parent, mResource); 
    } 
    public View getDropDownView(int position, View convertView, ViewGroup parent) { 
        return createViewFromResource(position, convertView, parent, mDropDownResource); 
    }
    

    可以看到getView和getDropDownView都通过调用createViewFromResourse来产生视图。

    private View createViewFromResource(int position, View convertView, ViewGroup parent, 
               int resource) { 
           View view; 
           TextView text; 
     
           if (convertView == null) { 
               view = mInflater.inflate(resource, parent, false); 
           } else { 
               view = convertView; 
           } 
     
           try { 
               if (mFieldId == 0) { 
                   //  If no custom field is assigned, assume the whole resource is a TextView 
                   text = (TextView) view; 
               } else { 
                   //  Otherwise, find the TextView field within the layout 
                   text = (TextView) view.findViewById(mFieldId); 
               } 
           } catch (ClassCastException e) { 
               Log.e("ArrayAdapter", "You must supply a resource ID for a TextView"); 
               throw new IllegalStateException( 
                       "ArrayAdapter requires the resource ID to be a TextView", e); 
           } 
     
           T item = getItem(position); 
           if (item instanceof CharSequence) { 
               text.setText((CharSequence)item); 
           } else { 
               text.setText(item.toString()); 
           } 
     
           return view; 
       }
    

    在createViewFromResource中,首先判断convertView是否存在,若不存在则inflate一个,然后判断mFieldID是否为0,若为0则表示传递给ArrayAdapter的资源ID为一TextView,否则是传递了一Layout,mFieldID为此Layout中TextView的ID。然后通过getItem取得相应位置的数据项,判断是否是CharSequence的实例,如果是直接setText,否则调用其toString()函数,可以ArrayAdapter默认只能给TextVext设置字符串,若要使用其他视图,需要重载getView或getDropDownView,一般情况下会继承BaseAdapter自定义自己的Adapter。

    在ArrayAdapter中,还有一静态函数

    public static ArrayAdapter<CharSequence> createFromResource(Context context, 
                int textArrayResId, int textViewResId) { 
            CharSequence[] strings = context.getResources().getTextArray(textArrayResId); 
            return new ArrayAdapter<CharSequence>(context, textViewResId, strings); 
        }
    

    读取资源文件中定义的字符数组作为数据生成ArrayAdapter,可以看到只能用TextView视图,而不可以指定一Layout再指定Layout中一个TextView的ID。

    在ArrayAdapter中还定义了一个ArrayFilter,继承自Filter,用于过滤数据项(当ListView有焦点时,通过键盘输入字符来进行列表项的过滤),其过滤方法为传入一CharSequence,判断相应数据项是否以此CharSequence开头,若不是则用空格分割些数据项,判断分割后的各字符串是否以此CharSequence开头,若是则保留(若数据不是CharSequence则调用其toString())。如果传入的CharSequence为null或长度为0则不过滤。

    CursorAdapter

    用于显示Cursor中的数据。

    在构造函数中可传递一参数autoRequery表示当cursor的数据改变时是否自动调用cursor的requery()以保持视图数据为最新的。

    此类中重写了hasStableIds(),返回true。

    public boolean hasStableIds() { 
        return true; 
    }
    

    在CursorAdapter中,重写的getView及getDropDownView判断传入的convertView是否为null,若为null及相应地调用newView()或newDropDownView()来生成一个视图,而newDropDownView()只有一条语句 return newView(context, cursor, parent);所以最后都是调用newView(),newView()为abstract的,需要由子类重写。

    当通过newView()产生一个View之后,会调用 bindView(v, mContext, mCursor);将cursor中的数据绑定到newView()产生的View之中,此方法同样为abstract的。

    CursorAdapter实现了接口CursorFilter.CursorFilterClient中的方法

    //改变cursor指向的数据
    public void changeCursor(Cursor cursor)
    //将cursor转变为CharSequence,返回""或调用cursor.toString()
    public CharSequence convertToString(Cursor cursor) 
    //过滤数据
    public Cursor runQueryOnBackgroundThread(CharSequence constraint)
    

    ResourceCursorAdapter

    如类名所示,该类继承自CursorAdapter,通过XML产生Views,该类只是简单地重写了一些函数,通过LayoutInflater.inflate将XML转换为View。

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) { 
        return mInflater.inflate(mLayout, parent, false); 
    } 
     
    @Override
    public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) { 
        return mInflater.inflate(mDropDownLayout, parent, false); 
    }
    

    SimpleCursorAdapter

    一个ResourceCursorAdapter的简单实现类,用于把cursor中相应的列映射为XML定义的视图中的TextView和ImageView。

    该类中定义了一个接口

    public static interface ViewBinder { 
        boolean setViewValue(View view, Cursor cursor, int columnIndex); 
    }
    

    用于设置把cursor中的列映射为视图的方法。

    在SimpleCursorAdapter中重写了bindView,控制cursor到视图的绑定,其定义如下

    @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"); 
                        } 
                    } 
                } 
            } 
        }
    

    可以看到,首先检查类中的私有域mViewBinder是否为null(默认为null,可通过setViewBinder)设置,为不为null则通过binder.setViewValue(v, cursor, from[i]); 进行绑定,这个函数若返回true则绑定成功,若返回false则通过SimpleCursorAdapter的规则绑定,判断相应的View是否为TextView或ImageView,若是则绑定,否则抛出异常。

    由些可以看到,我们可以自定义一个类实现SimpleCursorAdapter.ViewBinder,然后通过setViewBinder来改变bindView的结果。

    SimpleAdapter

    一个BaseAdapter的实现类,用于绑定数据到一个XML定义的视图中。数据类型为ArrayList<Map<String, ?>>。

    SimpleAdapter也实现了Filter接口用于数据的过滤,过滤方法类似ArrayAdapter,只是其数据类型为Map<String,?>,要判断Map中的每一项,若任意一顶符合要求就保留。

    SimpleAdapter也是通过bindView函数进行数据的绑定,同SimpleCursorAdapter一样,SimpleAdapter也定义了一个相同的内部接口ViewBinder,在bindView中,首先判断是否通过setViewBinder设置了ViewBinder,若设置了则调用其setViewValue进行数据绑定,如果没有设置其setViewValue返回了false,则进行下面的处理:依次判断View是否为Checkable,TextView,ImageView并进行相应的处理,可见默认情况下SimpleAdapter也是处理TextView与ImageView,当然可以setViewBinder。

    WrapperListAdapter

    继承自ListAdapder的接口,所以也是一个ListAdapter,同时里面嵌入了另一个ListAdapter,只定义了一个函数用于取得嵌入的ListAdapter。

    public ListAdapter getWrappedAdapter();
    

    HeaderViewListAdapter

    继承自WrapperListAdapter,当你使用的ListView有页首(Header Views)或页尾(Footer Views)时使用。此类被设计用来作为一个基类,一般不需要使用。

    类中定义了两个ArrayList用于保存页首和页尾

    ArrayList<ListView.FixedViewInfo> mHeaderViewInfos; 
    ArrayList<ListView.FixedViewInfo> mFooterViewInfos;
    

    这两个域不为null,在构造函数中判断,如果给这两个域赋值的参数为null,则将他们赋于值 HeaderViewListAdapter.EMPTY_INFO_LIST,其定义为

    static final ArrayList<ListView.FixedViewInfo> EMPTY_INFO_LIST = 
            new ArrayList<ListView.FixedViewInfo>();
    

    其中ListView.FixedViewInfo的定义为

    public class FixedViewInfo { 
        public View view;ListAdapter#getItem(int)}. 
        public Object data; 
        public boolean isSelectable; 
    }
    

    该类重定义了getCount,areAllItemsEnabled等函数,把mHeaderViewInfos,mFooterViewInfos同时包括在内。而hasStableIds,getItemViewType与getViewTypeCount只考虑了其内嵌的ListAdapter.

    我是天王盖地虎的分割线

    参考:http://www.cnblogs.com/fww330666557/archive/2012/01/11/2318944.html

  • 相关阅读:
    图解MBR分区无损转换GPT分区+UEFI引导安装WIN8.1 分类: Windows-嵌入式 生活百科 2015-06-26 11:57 475人阅读 评论(2) 收藏
    使用EFI引导从硬盘(U盘)安装Win7的图文教程 分类: Windows-嵌入式 生活百科 2015-06-25 16:40 320人阅读 评论(0) 收藏
    嵌入式Linux基于framebuffer的jpeg格式本地LCD屏显示 分类: TI-AM335X arm-linux-Ubuntu 2015-06-24 10:41 338人阅读 评论(0) 收藏
    Linux开机启动图片修改 分类: arm-linux-Ubuntu TI-AM335X 2015-06-19 16:12 390人阅读 评论(0) 收藏
    Linux下LCD 10分钟自动关屏的问题总结 分类: TI-AM335X arm-linux-Ubuntu 2015-06-19 15:43 369人阅读 评论(1) 收藏
    am335x在ubuntu下使用StarterWare编写裸机程序并在CCS中用Jlink调试 分类: TI-AM335X 2015-06-18 11:27 276人阅读 评论(0) 收藏
    IE 首页锁定
    LevelDb 资料整理
    c++ windows error C2662 C2663
    2018 ACM 网络选拔赛 青岛赛区
  • 原文地址:https://www.cnblogs.com/yydcdut/p/5042914.html
Copyright © 2020-2023  润新知