目录(?)[-]

  1. SimpleCursorAdapter
    1. 系统预置的layout
  2. ArrayAdapter
    1. 动态数据增插删排序
    2. 自定义TextView风格
  3. 其他Adapter

AdapterView不仅仅是UI,同时还将数据关联到UI上,例如在手机中经常使用的ListView就是AdapterView。

ListView、GridView、Spinner和Gallery都是AdapterView,AdapterView是ViewGroup,也就是容器,含有多个UI布局相同的子view。对于AdapterView,通过adapter将数据映射到子View中,一个AdapterView需要具体描述子view的布局,以及adapter如何将数据映射到每个子view上有1个或多个控件。

SimpleCursorAdapter

SimpleCursorAdapter是Adapter接口的的一个实现类,我们以ListView为例,具体分析其结构。

图的左部分,是ListView,由同样结构的子view组成,子view都对应同一个layout,可由xml文件进行描述,在里面放置一个或者多个控件,在本例中,放置一个TextView控件。由于子view对应同一个layout,因此每个子view里面的控件它的Resource id是一样的,因为这个资源id由同一layout指定。

图的右边部分,是数据源,例如Content Provider或者SQLite数据库,查询是返回一个cursor。adapter就是关联左边的ListView和右边的数据源的关键,它从数据源中读取某组数据,并关联到相应的某个子view,并将具体的数据在该子view布局中的控件中具体呈现。参考中写道:An Adapter object acts as a bridge between anAdapterView and the underlying data for that view.

下面,我们用一个简单的例子来进一步说明。我们在一个ListActivity上显示手机联系人的名字。Android的ListActivity,它的Layout中只含有一个全屏的的ListView,如果我们想使用自己的layout,有使用ListActivity,那么我们Layout中设置的ListView的ID必须为android:id="android:id/list"。在这个例子中,我们使用ListActivity缺省的布局。

public class UiAdapterDemo extendsListActivity{ //ListView需要集成系统的ListActivity
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState); 
        //将联系人信息读到Cursor中,这是个表格结构,每个联系人有多项详细。    
        CursorLoader cursorLoader = new CursorLoader(getApplicationContext(), 
                ContactsContract.Contacts.CONTENT_URI, 
                null, null, null, ContactsContract.Contacts.DISPLAY_NAME + " ASC");
        Cursor c = cursorLoader.loadInBackground();

       //在本例中,我们只需将联系人中的displayName,对应显示到子view中TextView控件上。from和to分别记录对应关系。注意,这是数据项和控件的一一对应。
        String[] from = {ContactsContract.Contacts.DISPLAY_NAME}; 
        int[] to = {android.R.id.text1}; 
        SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,  /* context */  
               android.R.layout.simple_list_item_1,   /* childLayout ID:子view的layout的Id,这里我们选用系统已经实现的一个简单的layout,它里面只一个TextView,id为android.R.id.text1,这就解释了为何在to中我们要填入此值 */ 
               c, /* 数据源: cursor*/ 
               from,
  /* 数据源中所选取数据项,本例中联系人有很多数据项,我们只选择displayName*/
               to, /* 这些数据项所对应的控件*/
               CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);  /* flag,从reference看,目前没有推荐用此值 ,当通知到来时(例如数据发生变化),触发onContentChanged() */
        this.setListAdapter(adapter);/*将Adapter适用于ListActivity的ListView*/
    }

本例读取联系人列表,需要在AndroidManifest.xml中进行权限声明:

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

ListView并不具体关心子view内呈现,而是将子view组织起来。AdapterView下面的ListView、GridView、Spinner、Gallery就是不同的子view组织方式。ListView是横排一行一行地呈现方式,当ListView要显示某行子view时,调用Adapter的getView(),getView()具体将数据源某row的from列数据在该行子view的控件中显示,如果我们要使用自己设计的layout,有可能需要overwrite该方法。如果屏幕只显示10行,原则上ListView只需获取该10行的子view,不需要将数百行都获取,但是实际上系统获取更多,目的是手指快速移动时,能更快地看到新行显示。

注意,我们这里用ListView为例子,但是通用方式也能使用与AdapterView的其他类型。

系统预置的layout

在例子中chlidLayout ID开头为android.R.,这表示为系统预设,而不是我们本地/res里面的资源。我们可以在SDK/plateforms/<android-version>/data/res/layout里面看到这些预设的布局。其中simple_list_item_1.xml文件如下:

<?xml version="1.0" encoding="utf-8"?> 
<!-- ...... --> 
<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@android:id/text1" <!-- 对应控件的ID:android.R.id.text1 -->
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:textAppearance="?android:attr/textAppearanceListItemSmall" 
    android:gravity="center_vertical" 
    android:paddingStart="?android:attr/listPreferredItemPaddingStart" 
    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" 
    android:minHeight="?android:attr/listPreferredItemHeightSmall" 
/>

ArrayAdapter

Cursor是二维表格数据源,更简单的情况就是一维的String[],直接和子View中唯一的TextView进行对应,这种情况可以使用最为简单的ArrayAdapter,如下所示。和SimpleCursorAdapter相比,由于是一维,不需要from和to进行对应。

ArrayAdapter<String> adapter = new ArrayAdapter<String> (this,  /* context */ 
        android.R.layout.simple_list_item_1, /* childLayout ID:子view的layout ID */
        new String[]{"Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"}); /*数据源: String[]*/
this.setListAdapter(adapter);

数据源可以来自资源的string-array。在/res/values下xml文件中定义。

<string-array name="planets"> 
        <item>Mercury</item> 
        <item>Venus</item> 
        <item>Earth</item> 
        <item>Mars</item> 
        <item>Jupiter</item> 
        <item>Saturn</item> 
        <item>Uranus</item> 
        <item>Neptune</item> 
    </string-array>

可以通过以下两种方式实现:

ArrayAdapter<String> adapter = new ArrayAdapter<String> (this, 
                android.R.layout.simple_list_item_1, 
                getResources().getStringArray(R.array.planets));

ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
                R.array.planets, android.R.layout.simple_list_item_1);

动态数据增,插,删,排序

ArrayAdapter可以进行动态的数据变更,使用add(), insert(), remove(), sort()。但是如果我们在上面的例子中进行adpater.add(“Pluto”);则系统会报告java.lang.NullPointerException。能够进行动态调整的前提是数据源可伸缩的,即size可以调整,而上面的例子,数据源实际上是String[8]。我们需改变一些代码,如下:

List<String> planents = new ArrayList<String>(); //采用ArrayList的可伸缩大小的数据格式所谓数据源 
initPlanets( planets) ; //对List的数据源进行初始化设置
adapter= new ArrayAdapter<String>(this,  android.R.layout.simple_list_item_1, planents);
this.setListAdapter(adapter); 
…… 
...... 
adapter.add("Pulto"); 
adapter.notifyDataSetChanged(); //在小例子中,无需加上这句也能生效,但仍建议加上,以确保同步

自定义TextView风格

ArrayAdapter有多个构造函数。我们使用自己定义风格的TextView,而不是用系统预置。例如我们在/res/layout/ui_my_textview.xml中设置:

<?xml version="1.0" encoding="utf-8"?> 
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:textColor="#005555" 
    android:id="@+id/my_textview" 
    android:layout_width="wrap_content" 
    android:layout_height="match_parent" >     
</TextView>

相关代码如下:

ArrayAdapter<String> adapter = new ArrayAdapter<String> (this, 
                    R.layout.ui_my_textview, /*子view的layout,由我们在资源中自行设定*/
                    R.id.my_textview,             /*子view中要填充数据的TextView的控件ID*/
                    getResources().getStringArray(R.array.planets));

此外,我们还可以在layout中嵌入AdapterView,例如ListView lv; lv.setAdapter(adapter);

其他Adapter

ArrayAdapter:认为子View的layout中只含有一个TextView。TextView中将填入Array中object.toString()的值。我们可以通过重写toString()来进行所需处理。如果不是TextView,则需重写getView(int,View, ViewGroup)函数,并返回View。

CursorAdapter:用于将cursor数据和ListView进行关联。其中cursor必须带有"_id"项,数据库SQLite的BaseColumns接口已带有此值。

SimpleAdapter:一般用于静态数据的,例如来自resource的数据。

ResourceCursorAdapter:是CursorAdapter的扩展,可以通过对XML资源的指定来创建各个子View。

SimpleCursorAdapter:是CursorAdapter的扩展,可以将cursor的数据和子View中的TextView或ImageView向映射。

我们将在后面的学习中使用到它们。

相关链接: 我的Android开发相关文章

【转】Pro Android学习笔记(十八):用户界面和控制(6):Adapter和AdapterView的更多相关文章

  1. 【转】 Pro Android学习笔记(八二):了解Package(1):包和进程

    文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ 在之前,我们已经学习了如何签发apk,见P ...

  2. 【转】 Pro Android学习笔记(八十):服务(5):访问远程服务

    目录(?)[-] Client的AIDL文件 Client的代码 建立连接 请求服务 断开连接 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://bl ...

  3. 【转】 Pro Android学习笔记(八八):了解Handler(2):什么是Handler

    文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ 之前我们有一篇很好的博文<Andro ...

  4. 【转】 Pro Android学习笔记(八九):了解Handler(3):延迟执行小例子

    目录(?)[-] 小例子 Handler的处理 Activity的代码片段 后台线程和UI的互动 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://b ...

  5. 【转】 Pro Android学习笔记(八六):了解Package(5):使用lib

    目录(?)[-] 在项目中使用lib 源代码 了解一些机制 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowin ...

  6. 【转】 Pro Android学习笔记(八四):了解Package(3):包间数据共享

    目录(?)[-] 共享User ID的设置 共享资源例子 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowing ...

  7. 【转】 Pro Android学习笔记(八五):了解Package(4):lib项目

    目录(?)[-] 什么是lib项目 小例子 Lib的实现 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowing ...

  8. 【转】 Pro Android学习笔记(八三):了解Package(2):包签名过程

    目录(?)[-] 类比例子 数字签名 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ 在W ...

  9. 【转】 Pro Android学习笔记(八七):了解Handler(1):组件和线程

    目录(?)[-] 主线程消息队列和线程池 查看线程信息 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingf ...

  10. 【转】Pro Android学习笔记(八):了解Content Provider(下中)

    在之前提供了小例子BookProvider,我们回过头看看如何将通过该Content Provider进行数据的读取. (1)增加 private void addBook(String name , ...

随机推荐

  1. cookie的坑

      HTTP Cookie       设置了secure ,   该cookie只能在HTTPS通道下被写入浏览器. HTTPS Cookie     设置了secure ,   该cookie只能 ...

  2. redis持久化AOF详细操作步骤

    1.切换到redis目录下面,创建文件 s3-redis.conf 2.编辑文件s3-redis.conf 3.终止当前redis服务端 4.登录redis客户端失败,说明服务端已停止 5.重启red ...

  3. Kafka具体解释二、怎样配置Kafka集群

    Kafka集群配置比較简单,为了更好的让大家理解.在这里要分别介绍以下三种配置 单节点:一个broker的集群 单节点:多个broker的集群 多节点:多broker集群 一.单节点单broker实例 ...

  4. 17.Django表单验证

    Django提供了3中方式来验证表单 官网文档:https://docs.djangoproject.com/en/1.9/ref/validators 1.表单字段验证器 a.引入:from dja ...

  5. go语言之并发编程 channel(1)

    单向channel: 单向通道可分为发送通道和接收通道.但是无论哪一种单向通道,都不应该出现在变量的声明中,假如初始化了这样一个变量 var uselessChan chan <- int =m ...

  6. xpath中如何使用变量

    xpath (python)xpath中如何使用变量描述: 在xpath中该如何使用变量,想选择id是某个值的元素,这个值是个变量. response.xpath('//div[@id=val]'). ...

  7. python学习-1-列表,元组,字典,集合,文件操作

    1. 列表.元组操作 names = ['Alex',"Tenglan",'Eric'] >>> names[0] >>> names[2] & ...

  8. 【Mybatis】Insert批量操作

    话不多说,直接上代码. <insert id="pesistRT" parameterType="com.test.model.RTSummarizer" ...

  9. 第14条:尽量用异常来表示特殊情况,而不要返回Nono

    核心知识点: 1.用None这个返回值来表示特殊意义的函数,很容易使调用者犯错,因为None和0以及空字符串之类的值,在条件表达式里都会评估为False. 2.两种方法:二元法:将异常抛给上一级直接报 ...

  10. 扣出thinkphp数据库操作类

    假如你是一位thinkphp的使用者,想必你会觉得thinkphp操作数据库非常方便.现在在你面前有一个非常小的作业,小到完全没有必要用thinkphp去完成它.但是你又觉得不用thinkphp的话, ...