`

Android Adapter详解

阅读更多

Adapter是用来帮助填充数据的中间桥梁,比如通过它将数据填充到ListView, GridView, Gallery.而android 提供了几种Adapter:ArrayAdapter, BaseAdapter, CursorAdapter, HeaderViewListAdapter, ListAdapter, ResourceCursorAdapter, SimpleAdapter, SimpleCursorAdapter, SpinnerAdapter, WrapperListAdapter.

 

根据数据来源形式的不同可以选择不同的Adapter,比如数据来源于一个Arraylist 就使用BaseAdapter,SimpleAdapter,而数据来源于通过查询数据库获得Cursor那就使用CursorAdapter

 

适配器的继承结构



 

Data、Adapter、View三者的关系



 

 

Adapter应用总结

 

首先来看一下Adapter的体系结构:

 

一个Adapter的对象扮演一个桥梁的角色。这个桥梁连接着一个AdapterView和它所包含的数据。Adapter提供了一个通到数据项的途径。Adapter还负责为在数据集里的每个数据生项生成一个View。它有一个重要的方法:

public abstract View getView (int position,View convertView,ViewGroup parent)

这个方法被setListAdapter(adapter)间接地调用。getView 方法的作用是得到一个View,这个view显示数据项里指定位置的数据,你可以或者手动创建一个view或者从一个XML layout中inflate。当这个view被inflated,它的父view(如GridView,ListView等)将要使用默认的layout参数,除非你用inflate(int,android.view.ViewGroup,boolean)方法来指定一个根view并防止附着在根上。

 

下面分别讲一下它的几个常见的子类:

 

ListAdapter接口:继承于Adapter。ListAdapter是一个ListView和list上的数据之间的桥梁。数据经常来自于一个Cursor,但这不是必须的。ListView能显示任何数据,只要它是被一个ListAdapter包装的。

 

BaseAdapter抽象类:是一个实现了既能在ListView(实现了ListAdapter接口)和Spinner(实现了Spinner接口)里用的Adapter类的一般基类。

 

ArrayAdapter类:一个管理这样的ListView的ListAdapter:这个ListView被一个数组所支持。这个数组可装任意对象。默认状态下,这个类预期能这样:提供的资源id与一个单独的TextView相关联。如果你想用一个更复杂的layout,就要用包含了域id的构造函数。这个域id能够与一个在更大的layout资源里的TextView相关联。它将被在数组里的每个对象的toString()方法所填满。你可以添加通常对象的lists或arrays。重写你对象的toString()方法来决定list里哪一个写有数据的text将被显示。如果想用一些其它的不同于TextView的view来显示数组(比如ImageViews),或想有一些除了toString()返回值所填在views里的以外的数据,你就要重写getView(int,View,ViewGroup)方法来返回你想要的View类型。

 

SimpleAdapter类:一个使静态数据和在XML中定义的Views对应起来的简单adapter。你可以把list上的数据指定为一个Map范型的ArrayList。ArrayList里的每一个条目对应于list里的一行。Maps包含着每一行的数据。你先要指定一个XML,这个XML定义了用于显示一行的view。你还要指定一个对应关系,这个对应关系是从Map的keys对应到指定的views。

 

SimpleCursorAdapter可以适用于简单的纯文字型ListView,它需要Cursor的字段和UI的id对应起来。如需要实现更复杂的UI也可以重写其他方法。一定要以数据库作为数据源的时候,才能使用SimpleCursorAdapter,这里特别需要注意的一点是:不要忘了在AndroidManifest.xml文件中加入权限:

<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>

 

 应用案例

1)ArrayAdapter

列表的显示需要三个元素:

a.ListVeiw 用来展示列表的View。

b.适配器 用来把数据映射到ListView上的中介。

c.数据    具体的将被映射的字符串,图片,或者基本组件。

案例一

复制代码
public class ArrayAdapterActivity extends ListActivity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         //列表项的数据         String[] strs = {"1","2","3","4","5"};
         ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_expandable_list_item_1,strs);
         setListAdapter(adapter);
     }
 }
复制代码

案例二

复制代码
    public class MyListView extends Activity {
    
        private ListView listView;
        //private List<String> data = new ArrayList<String>();        @Override
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
             
            listView = new ListView(this);
            listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1,getData()));
            setContentView(listView);
        }
         
        private List<String> getData(){
             
            List<String> data = new ArrayList<String>();
            data.add("测试数据1");
            data.add("测试数据2");
            data.add("测试数据3");
            data.add("测试数据4");
             
            return data;
        }
    }

 

 

        上面代码使用了Adapter(Context context, int resourcefulness, List<T> objects)来装配数据,要装配这些数据就需要一个连接List View视图对象和数组数据的适配器来两者的适配工作,Adapter的构造需要三个参数,依次为this,布局文件(注意这里的布局文件描述的是列表的每一行的布局,android.R.layout.simple_list_item_1是系统定义好的布局文件只显示一行文字,数据源(一个List集合)。同时用adapter()完成适配的最后工作。效果图如下:

 

2)SimpleAdapter
  simpleAdapter的扩展性最好,可以定义各种各样的布局出来,可以放上ImageView(图片),还可以放上Button(按钮),CheckBox(复选框)等等。下面的代码都直接继承了ListActivity,ListActivity和普通的Activity没有太大的差别,不同就是对显示ListView做了许多优化,方面显示而已。

案例一

simple.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:textColor="#ffffff"
android:textSize="20sp"/>
</LinearLayout>
复制代码
复制代码
public class SimpleAdapterActivity extends ListActivity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         
         SimpleAdapter adapter = new SimpleAdapter(this, getData(), R.layout.simple, new String[] { "title",  "img" }, new int[] { R.id.title, R.id.img });
         setListAdapter(adapter);
     }
     
     private List<Map<String, Object>> getData() {
         //map.put(参数名字,参数值)         List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
         Map<String, Object> map = new HashMap<String, Object>();
         map.put("title", "摩托罗拉");
         map.put("img", R.drawable.icon);
         list.add(map);
         
         map = new HashMap<String, Object>();
         map.put("title", "诺基亚");
         map.put("img", R.drawable.icon);
         list.add(map);
         
         map = new HashMap<String, Object>();
         map.put("title", "三星");
         map.put("img", R.drawable.icon);
         list.add(map);
         return list;
         }  
     
 }
复制代码

案例二
  下面的程序是实现一个带有图片的类表。首先需要定义好一个用来显示每一个列内容的xml,vlist.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent"
        android:layout_height="fill_parent">   
        <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5px"/>
        <LinearLayout android:orientation="vertical"  android:layout_width="wrap_content"  android:layout_height="wrap_content">
            <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content"
                android:textColor="#FFFFFFFF" android:textSize="22px" />
            <TextView android:id="@+id/info"  android:layout_width="wrap_content" android:layout_height="wrap_content"
                android:textColor="#FFFFFFFF" android:textSize="13px" />
        </LinearLayout>
     </LinearLayout>
复制代码
复制代码
public class MyListView3 extends ListActivity {
        // private List<String> data = new ArrayList<String>();        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
     
            SimpleAdapter adapter = new SimpleAdapter(this,getData(),R.layout.vlist,
                    new String[]{"title","info","img"},
                    new int[]{R.id.title,R.id.info,R.id.img});
            setListAdapter(adapter);
        }
     
        private List<Map<String, Object>> getData() {
            List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
     
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("title", "G1");
            map.put("info", "google 1");
            map.put("img", R.drawable.i1);
            list.add(map);
     
            map = new HashMap<String, Object>();
            map.put("title", "G2");
            map.put("info", "google 2");
            map.put("img", R.drawable.i2);
            list.add(map);
     
            map = new HashMap<String, Object>();
            map.put("title", "G3");
            map.put("info", "google 3");
            map.put("img", R.drawable.i3);
            list.add(map);
             
            return list;
        }
    }

 

 

  使用Impleader的数据用一般都是Hash Map构成的List,list的每一节对应Listie的每一行。Hash Map的每个键值数据映射到布局文件中对应id的组件上。因为系统没有对应的布局文件可用,我们可以自己定义一个布局alist.XML。下面做适配,new一个Impleader参数一次是:this,布局文件(alist.XML),Hash Map的 title 和 info,IgM。布局文件的组件id,title,info,IgM。布局文件的各组件分别映射到Hash Map的各元素上,完成适配。

运行效果如下图:

 

3)SimpleCursorAdapter

复制代码
public class SimpleCursorAdapterActivity extends ListActivity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         //获得一个指向系统通讯录数据库的Cursor对象获得数据来源         Cursor cur = getContentResolver().query(People.CONTENT_URI, null, null, null, null);
         startManagingCursor(cur);
         //实例化列表适配器         
         ListAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cur, new String[] {People.NAME}, new int[] {android.R.id.text1});
         setListAdapter(adapter);
     }
 }
复制代码

一定要以数据库作为数据源的时候,才能使用SimpleCursorAdapter,这里特别需要注意的一点是:不要忘了在AndroidManifest.xml文件中加入权限

<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>

 

效果如下:

 

4)BaseAdapter

  有时候,列表不光会用来做显示用,我们同样可以在在上面添加按钮。添加按钮首先要写一个有按钮的xml文件,然后自然会想到用上面的方法定义一个适配器,然后将数据映射到布局文件上。但是事实并非这样,因为按钮是无法映射的,即使你成功的用布局文件显示出了按钮也无法添加按钮的响应,这时就要研究一下ListView是如何现实的了,而且必须要重写一个类继承BaseAdapter。下面的示例将显示一个按钮和一个图片,两行字如果单击按钮将删除此按钮的所在行。并告诉你ListView究竟是如何工作的。

vlist2.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5px"/>
        <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content">
           <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content"
                android:textColor="#FFFFFFFF" android:textSize="22px" />
           <TextView android:id="@+id/info" android:layout_width="wrap_content" android:layout_height="wrap_content"
                android:textColor="#FFFFFFFF" android:textSize="13px" />
       </LinearLayout>

       <Button android:id="@+id/view_btn" android:layout_width="wrap_content"  android:layout_height="wrap_content"
            android:text="@string/s_view_btn" android:layout_gravity="bottom|right" />
    </LinearLayout>

 

/**
* @author 
*
*/
public class MyListView4 extends ListActivity {   
     
    private List<Map<String, Object>> mData;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mData = getData();
        MyAdapter adapter = new MyAdapter(this);
        setListAdapter(adapter);
    }
     
    private List<Map<String, Object>> getData() {
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
    
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("title", "G1");
        map.put("info", "google 1");
        map.put("img", R.drawable.i1);
        list.add(map);
    
        map = new HashMap<String, Object>();
        map.put("title", "G2");
        map.put("info", "google 2");
        map.put("img", R.drawable.i2);
        list.add(map);
     
        map = new HashMap<String, Object>();
        map.put("title", "G3");
        map.put("info", "google 3");
        map.put("img", R.drawable.i3);
        list.add(map);
             
        return list;
    }
         
    // ListView 中某项被选中后的逻辑
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {         
        Log.v("MyListView4-click", (String)mData.get(position).get("title"));
    }
         
    /**
    * listview中点击按键弹出对话框
    */
    public void showInfo(){
        new AlertDialog.Builder(this)
            .setTitle("我的listview")
            .setMessage("介绍...")
            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) { }}).show();
    }
    
    /** 当Listie有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候   就需要按需填充并重新使用    *view来减少对象的创建
    *最快的方式是定义一个Pewholder,将convex的tag设置为Pewholder,不为空时重新使用即可
    */
    public final class ViewHolder{
        public ImageView img;
        public TextView title;
        public TextView info;
        public Button viewBtn;
    }     
         
    public class MyAdapter extends BaseAdapter{
     
        private LayoutInflater mInflater;      
             
        public MyAdapter(Context context){
            this.mInflater = LayoutInflater.from(context);
        }
        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return mData.size();
        }
     
        @Override
        public Object getItem(int arg0) {
            // TODO Auto-generated method stub
            return null;
        }
     
        @Override
        public long getItemId(int arg0) {
            // TODO Auto-generated method stub
            return 0;
        }
     
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
                 
            ViewHolder holder = null;
            if (convertView == null) {             
                holder=new ViewHolder();     
                convertView = mInflater.inflate(R.layout.vlist2, null);
                holder.img = (ImageView)convertView.findViewById(R.id.img);
                holder.title = (TextView)convertView.findViewById(R.id.title);
                holder.info = (TextView)convertView.findViewById(R.id.info);
                holder.viewBtn = (Button)convertView.findViewById(R.id.view_btn);
                convertView.setTag(holder);         
            }else {
                holder = (ViewHolder)convertView.getTag();
            }

            holder.img.setBackgroundResource((Integer)mData.get(position).get("img"));
            holder.title.setText((String)mData.get(position).get("title"));
            holder.info.setText((String)mData.get(position).get("info"));
            holder.viewBtn.setOnClickListener(new View.OnClickListener() {
                     
                @Override
                public void onClick(View v) {
                    showInfo();                
                }});
           return convertView;
       }
    }     
}

 

 

下面将对上述代码,做详细的解释,listView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到listView的长度,然后根据这个长度,调用getView()逐一绘制每一行。如果你的getCount()返回值是0的话,列表将不显示同样return 1,就只显示一行。

  系统显示列表时,首先实例化一个适配器(这里将实例化自定义的适配器)。当手动完成适配时,必须手动映射数据,这需要重写getView()方法。系统在绘制列表的每一行的时候将调用此方法。getView()有三个参数,position表示将显示的是第几行,covertView是从布局文件中inflate来的布局。我们用LayoutInflater的方法将定义好的vlist2.xml文件提取成View实例用来显示。然后将xml文件中的各个组件实例化(简单的findViewById()方法)。这样便可以将数据对应到各个组件上了。但是按钮为了响应点击事件,需要为它添加点击监听器,这样就能捕获点击事件。至此一个自定义的listView就完成了,现在让我们回过头从新审视这个过程。系统要绘制ListView了,他首先获得要绘制的这个列表的长度,然后开始绘制第一行,怎么绘制呢?调用getView()函数。在这个函数里面首先获得一个View(实际上是一个ViewGroup),然后再实例并设置各个组件,显示之。好了,绘制完这一行了。那再绘制下一行,直到绘完为止。在实际的运行过程中会发现listView的每一行没有焦点了,这是因为Button抢夺了listView的焦点,只要布局文件中将Button设置为没有焦点就OK了。

效果如下:

 

  • 大小: 57.2 KB
  • 大小: 26.6 KB
  • 大小: 16.3 KB
  • 大小: 25.3 KB
  • 大小: 15 KB
分享到:
评论

相关推荐

    android adapter详解

    android adapter适配器详解

    Android adapter详解

    个人整理的关于adapter的详细讲解,文章图文并茂,从简单到复杂,从原理到实践。让你更好更快的理解adapter。

    Android Adapter详解(2)

    NULL 博文链接:https://18767136122.iteye.com/blog/1995973

    android开发Adapter详解

    android开发Adapter详解,帮助你加深进一步的理解···

    Android listview与adapter详解及实例代码

    本文主要介绍Android listview与adapter的知识详解,这里整理了相关资料及实现代码和实现效果图,有兴趣的小伙伴可以参考下

    Android Adapter里面嵌套ListView实例详解

    主要介绍了Android Adapter里面嵌套ListView实例详解的相关资料,这里提供实例代码并说明如何实现该功能,需要的朋友可以参考下

    Android ListView

    Android ListView 详解,适配器adapter详解 博客地址:http://blog.csdn.net/csdnyuandaimaxuexi/article/details/48808303

    Android基础知识详解

    自定义Adapter来建立复杂的列表项 99 动态添加、删除ListView列表项 102 改变ListView列表项选中状态的背景颜色 102 可展开的列表组件 102 数据的存取 103 SharePreferences 6.1 103 文件的存储6.2 103 SQLite数据库...

    Android学习资料

    收集的一些关于Android的学习...Android之Adapter用法总结,Android中图片的处理,BaseExpandableListAdapter的使用,反编译android app,详解 Android 的 Activity 组件,需要的朋友可以下载查看(直接双击html文件查看即可)

    Android ListView的OnItemClickListener详解

    我们在使用ListView的时候,一般都会为ListView添加一个响应事件android.widget.AdapterView.OnItemClickListener。本文主要在于对OnItemClickListener的position和id参数做详细的解释,我相信有些人在这上面走了些...

    Android RecyclerView网格布局(支持多种分割线)详解(2)

    上篇Android RecyclerView 详解(1)—线性布局 记录了下RecyclerView的使用方法,并且讲述了线性布局列表的使用方法,在此基础上加上了万能分割线,支持颜色分割线和图片分割线,同时支持对分割线设置线宽。 这篇...

    Android ListView适配器(Adapter)优化方法详解

    Android ListView的优化,在做Android项目的时候,在用到ListView 界面及数据显示,这个时候如果资源过大,对项目来说,用户体验肯定是不好的,这里就对如何优化做了详细介绍: Adapter的作用就是ListView界面与数据...

    MultiItem用法与详解-优雅的实现多类型RecyclerView Adapter

    参考 MultiItem用法与详解-优雅的实现多类型RecyclerView Adapter(https://www.jianshu.com/p/7dc7c8201a90),在此感谢作者。我在MyInputDemoActivity中又添加了表单项验证、弹出popwindow的表单项、省市区三级...

    Android SimpleAdapter适配器使用详解

    Android SimpleAdapter使用详解 HolderAdapter背景 Android的AdapterView用的比较多,ListView,GridView,Spinner等,原生的BaseAdapter对ViewHolder没有支持,每次都要,定义内部类,inflater根布局,对item内部...

    简单好用的Adapter---ArrayAdapter详解

    主要介绍了简单好用的Adapter---ArrayAdapter详解,具有一定参考价值,需要的朋友可以了解下。

    android studio 的下拉菜单Spinner使用详解

    Spinner 与 Gallery 都继承了AbsSpinner,AbsSpinner 继承了AdapterView,因此它也表现出AdapterView的特征:只要为AdapterView提供Adapter即可。 1.相关属性 android:dropDownHorizontalOffset:设置列表框的水平...

    android开发教程之自定义属性用法详解

    最近项目中经常需要用到自定义控件,因此自定义属性也是经常要用到的,在此说明一下自定义属性的用法: 自定义属性都存在于/value/attr.xml文件中,以如下格式存在。 代码如下: ”自定义属性名称”&gt; ...

Global site tag (gtag.js) - Google Analytics