连接AdapterView视图和数据源的桥梁:Adapter适配器(3)

BaseAdapter是一种使用频率较高的适配器,因为它可以通过自定义最大程度扩展满足各种情景下的使用。我们不仅需要知道适配器的使用,进一步我们也需要了解适配器的原理。

问题是最好的学习方式,下面主要讨论这么几个问题:

Q1.ListView中每个Item的创建

Q2.ListView中Item的复用

Q3.ListView中屏幕显示的Item与复用生成Item之间的关系

  首先写一个简单的demo.

 1 package com.aellenlei.baseadapterdemo;
 2
 3 import android.support.v7.app.AppCompatActivity;
 4 import android.os.Bundle;
 5 import android.widget.ListView;
 6
 7 import java.util.ArrayList;
 8 import java.util.List;
 9
10 public class MainActivity extends AppCompatActivity {
11
12     @Override
13     protected void onCreate(Bundle savedInstanceState) {
14         super.onCreate(savedInstanceState);
15         setContentView(R.layout.activity_main);
16
17         //1.findViewById
18         ListView listView = (ListView) findViewById(R.id.listView);
19
20         //2.初始化数据源
21         List<ItemBean> list = new ArrayList<>();
22         for (int i = 0; i < 5; i++) {
23             ItemBean itemBean = new ItemBean();
24             itemBean.postion = i;
25             itemBean.title = "title " + i;
26             itemBean.content = "content " + i;
27             list.add(itemBean);
28         }
29
30         //3.初始化适配器
31         ItemBeanAdapter itemBeanAdapter = new ItemBeanAdapter(list, getApplicationContext());
32
33         //4.ListView绑定适配器
34         listView.setAdapter(itemBeanAdapter);
35     }
36 }

MainActivity.java

 1 package com.aellenlei.baseadapterdemo;
 2
 3 import android.content.Context;
 4 import android.util.Log;
 5 import android.view.LayoutInflater;
 6 import android.view.View;
 7 import android.view.ViewGroup;
 8 import android.widget.BaseAdapter;
 9 import android.widget.CheckBox;
10 import android.widget.ImageView;
11 import android.widget.TextView;
12
13 import java.util.List;
14
15 /**
16  * User AellenLei
17  * NAME ItemBeanAdapter
18  * DATE 2016/3/7
19  */
20 public class ItemBeanAdapter extends BaseAdapter {
21
22     private List<ItemBean> mData;
23     private Context mContext;
24
25     public ItemBeanAdapter(List<ItemBean> mData, Context mContext) {
26         this.mData = mData;
27         this.mContext = mContext;
28     }
29
30     @Override
31     public int getCount() {
32         return mData == null ? 0 : mData.size();
33     }
34
35     @Override
36     public ItemBean getItem(int position) {
37         return mData.get(position);
38     }
39
40     @Override
41     public long getItemId(int position) {
42         return position;
43     }
44
45     @Override
46     public View getView(int position, View convertView, ViewGroup parent) {
47
48         Log.d("msg", position + "," + getItem(position).postion + "," + getItem(position).title + ".  "
49                 + ((convertView == null) ? ("covertView = null") :
50                 (((TextView) convertView.findViewById(R.id.item_title)).getText().toString()))
51         );
52
53
54         View ret;
55
56         if (convertView != null) {
57             ret = convertView;
58         } else {
59             ret = LayoutInflater.from(mContext).inflate(R.layout.item, null);
60             ViewHolder holder = new ViewHolder();
61             holder.itemIcon = (ImageView) ret.findViewById(R.id.item_icon);
62             holder.itemTitle = (TextView) ret.findViewById(R.id.item_title);
63             holder.itemContent = (TextView) ret.findViewById(R.id.item_content);
64             holder.itemDate = (TextView) ret.findViewById(R.id.item_date);
65             holder.itemChecked = (CheckBox) ret.findViewById(R.id.item_check);
66             ret.setTag(holder);
67         }
68
69         ViewHolder viewHolder = (ViewHolder) ret.getTag();
70
71         ItemBean itemBean = getItem(position);
72
73         viewHolder.itemIcon.setImageResource(R.mipmap.ic_launcher);
74         viewHolder.itemTitle.setText(itemBean.title);
75         viewHolder.itemContent.setText(itemBean.content);
76         viewHolder.itemDate.setText("yyyy-MM-dd");
77         viewHolder.itemChecked.setChecked(itemBean.check);
78
79         return ret;
80     }
81
82     private static class ViewHolder {
83         private ImageView itemIcon;
84         private TextView itemTitle;
85         private TextView itemContent;
86         private TextView itemDate;
87         private CheckBox itemChecked;
88     }
89 }

ItemBeanAdapter

 1 package com.aellenlei.baseadapterdemo;
 2
 3 /**
 4  * User AellenLei
 5  * NAME ItemBean
 6  * DATE 2016/3/7
 7  */
 8 public class ItemBean {
 9     public int postion;
10     public String url;
11     public String title;
12     public String content;
13     public String date;
14     public boolean check;
15 }

ItemBean

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:tools="http://schemas.android.com/tools"
 4     android:layout_width="match_parent"
 5     android:layout_height="match_parent"
 6     android:paddingBottom="@dimen/activity_vertical_margin"
 7     android:paddingLeft="@dimen/activity_horizontal_margin"
 8     android:paddingRight="@dimen/activity_horizontal_margin"
 9     android:paddingTop="@dimen/activity_vertical_margin"
10     tools:context=".MainActivity">
11
12     <ListView
13         android:id="@+id/listView"
14         android:layout_width="match_parent"
15         android:layout_height="match_parent"/>
16 </RelativeLayout>

activity_main.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:padding="8dp">
 6
 7     <ImageView
 8         android:id="@+id/item_icon"
 9         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:src="@mipmap/ic_launcher"
12         android:padding="4dp"/>
13
14     <TextView
15         android:id="@+id/item_title"
16         android:layout_width="wrap_content"
17         android:layout_height="wrap_content"
18         android:textSize="20sp"
19         android:textStyle="bold"
20         android:layout_toRightOf="@id/item_icon"
21         android:layout_alignTop="@id/item_icon"/>
22     <TextView
23         android:id="@+id/item_content"
24         android:layout_width="wrap_content"
25         android:layout_height="wrap_content"
26         android:textSize="16sp"
27         android:layout_below="@id/item_title"
28         android:layout_toRightOf="@id/item_icon"
29         android:layout_alignBottom="@id/item_icon"/>
30
31     <TextView
32         android:id="@+id/item_date"
33         android:layout_width="wrap_content"
34         android:layout_height="wrap_content"
35         android:layout_toRightOf="@id/item_title"
36         android:layout_alignParentRight="true"
37         android:gravity="right"/>
38     <CheckBox
39         android:id="@+id/item_check"
40         android:layout_width="wrap_content"
41         android:layout_height="wrap_content"
42         android:text="@null"
43         android:layout_below="@id/item_date"
44         android:layout_alignParentRight="true"
45         android:gravity="center"
46         android:layout_alignBottom="@id/item_content"/>
47 </RelativeLayout>

item.xml

由于该Demo比较简单,不需多讲相信都可以看懂。

ItemBeanAdapter.java的getView方法中有这么一句:

  

 分别打印的是ListView中每一个Item在ListView中的位置(默认从0开始,下同),该Item显示的数据源中指定位置数据的poistion和title,convertView是否为空若不为空打印convertView之前显示的title.

 当数据源中的数据条数为5时,Logcat的日志:

  

  UI:

  

 当数据源中的数据条数为10是,Logcat的日志:

  

  UI:

  

  

  根据这两种情况的测试,可以大概回答第一个问题:

Q1.ListView中每个Item的创建

A1.Adapter第一次创建的Items的数量是由手机屏幕的大小(可测试)和数据源数据的条数来决定的,也就是屏幕实际显示多少个Item就创建几个item的,不多创建新的item也不少创建新的item,items数量是屏幕实际显示数目的取整。将下面的完整结合来看,第一次创建的Item是最基本的Item,它的数量是确定的,以后新的item无论是向上滑动出现还是向下滑动出现都是复用第一次创建的items中的某个item。

Q2.ListView中Item的复用

A2:最核心的代码就是Adapter中的getView方法,它返回的是一个已经绑定好数据的view,而系统仅仅只是将这个view在屏幕的指定位置绘制出来。

  

  代码不是固定死的,当然你可以有自己的写法,但是原理总是相同的:

    A2:当ListView第一次创建一屏幕的items时,covertView始终为null(代码测试很容易得出),所以当covertView为空时,就需要将第一次创建一屏幕的items的每个item“初始化”,这里的“初始化”是将covertView和ViewHolder绑定起来,注意不论是将covertView和ViewHolder绑定起来还是ret和ViewHolder绑定起来,它们的本质是一样的,最后返回值是已经与ViewHolder绑定的View视图,当掌握了covertView的复用写法,可以说是基本上item的复用的写法也掌握了。

    注意下面一种情况,当ListView向上滑动,且item0完全不见,item7和item8出现(下图item8已经出现,只是没有完全显示)的情况:

    

    此时Logcat打印的日志:

      

    根据之前的第一次创建items打印的日志比较:item7仍然是新创建的,但是item8却是复用的,item8复用的是item0(完全根据日志得出的)。(PS 可能此处有疑问,下面会分析)

    A2:当listView向上滑动或者是向下滑动的时候,此时可能会出现item复用的情况(注意此时可能会出现复用的情况,不一定或出现哦)。若covertView不为空,就可以之前在该covertView初始化或复用中通过getTag方法,取出与之绑定的ViewHolder,从而实现减少findViewById的时间,findViewById是需要耗费时间的,当listView显示大量的数据,此时的findViewByid可以极大的提高效率。

    最后分析总结前面的,可以回答第三个问题:

Q3.ListView中屏幕显示的Item与复用生成Item之间的关系

A3:ListView实际创建item的数量是由手机屏幕的大小和数据源的数据数量来决定的,准确的将这是不准确的或是错误的。

  ListView在整个复用过程中本质上实际创建item的数量(这里所指的全部是最原始最本质的item)是由手机屏幕的大小、数据源的数据数量和每个item实际的大小来决定的(当然这里不考虑其他更为负责的情况,而是假定每个item的大小相同)。

   用可以唯一衡量确定的话说是:本质上items的数量是当第一个item完全消失后,此时Adapter总共创建的items数量,从本质上来说,这就是ListView在整个复用过程中复用的item的数量。假如从0,1,...,n-1(n为最原始的item数量)来看,当ListView向上滑动时,复用tem的顺序是按顺序复用0,1,...,n-1,每次复用一个;当ListView向下滑动时,复用的顺序是按照逆序的,从n-1,n-2,..,0,也是一个一个复用的。

  当然还有更为复杂的情况或者说从更为本质也就是源码的角度分析,这里暂不考虑,而是从一种最为表象或者最最最基本最最简单来分析ListView与Adapter。

 

时间: 2024-10-05 16:35:24

连接AdapterView视图和数据源的桥梁:Adapter适配器(3)的相关文章

连接AdapterView视图和数据源的桥梁:Adapter适配器(2)

BaseAdapter是一种原生态的适配器,它是一个抽象类,一般使用它来实现自定义的适配器,当需要适配大量的数据时,为了节省手机的内存,往往会定义一个类继承它,从而优化内存的使用,使用在ListView.Spinner的内存效率优化. 查询Android官方文档可知BaseAdapter的类定义 BaseAdapter是直接继承Java中顶级类Object类,同时它实现了ListAdapter和SpinnerAdapter接口.BaseAdapter的常用直接子类有ArrayAdapter<T>

【边做项目边学Android】知识点:Adapter适配器

1.概念 Adapter是连接后端数据和前端显示的适配器接口,是数据和UI(View)之间一个重要的纽带.在常见的 View(ListView,GridView)等地方都需要用到Adapter.如下图直观的表达了Data.Adapter.View三者的关系: Android中所有的Adapter一览: 由图可以看到在Android中与Adapter有关的所有接口.类的完整层级图.在我们使用过程中可以根据自己的需求实现接口或者继承类进行一定的扩展.比较常用的有 BaseAdapter,Simple

Loadrunner参数化连接oracle、mysql数据源报错及解决办法

Loadrunner参数化连接oracle.mysql数据源报错及解决办法 (本人系统是Win7 64,  两位小伙伴因为是默认安装lr,安装在 最终参数化的时候,出现连接字符串无法自动加载出来: 最后通过安装在,问题到此解决 1.通过数据库连接参数化大量数据,电脑本地已经成功安装了数据库驱动,且本地可以配置数据源成功,在loadrunner 中配置数据源却找不到对应的数据库驱动. ----A:检查当前loadrunner工具的版本,是32位还是64位(目前还没有64位的),32位是不能安装64

php -- 解决php连接sqlserver2005视图时显示“异类查询要求为连接设置 ANSI_NULLS 和 ANSI_WARNINGS 选项”的问题

--php5.2 --sqlserver2005 php连接sqlserver的视图aa,语句如下: $query = mssql_query("select * from dbo.aa",$conn); warming:“异类查询要求为连接设置 ANSI_NULLS 和 ANSI_WARNINGS 选项.这将确保一致的查询语义.请启用这些选项,然后重新发出查询.” 于是上网查资料@[email protected]~  打开查询分析器,做了如下设置: SET ANSI_NULLS O

Android adapter适配器的使用

ListView之SimpleAdapter SimpleAdapter的构造函数是: public SimpleAdapter (Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) 参数context:上下文,比如this.关联SimpleAdapter运行的视图上下文 参数data:Map列表,列表要显示的数据,这部分需要自己实现,如例子中的ge

android学习笔记之ListView 和Adapter适配器

1.在学习Listview时候用到了Adapter适配器,定义MyAdapter时候需要继承ListAdapter接口,接口里很多方法没有实现,为了方便google工程师实现了个BaseAdapter类,我们在使用的时候可以继承这个抽象类,因此我们只需要完成几个抽象方法就可以了. public class Db_adapter extends BaseAdapter { private Context context; private List<Person> personlist; publ

设计模式之适配器模式 adapter 适配器模式分类概念角色详解 类适配器 对象适配器 接口适配器 双向适配器

现实世界中的适配器模型 先来看下来几个图片,截图自淘宝 上图为港版的插头与港版的插座 上图为插座适配器卖家的描述图 上图为适配后的结果 现实世界中适配器模式 角色分类 这就是适配器模式在电源插座上的应用 我们看下在插座适配器中的几个重要角色 可以看得出来,大陆和港版插座面板,都是作为电源的角色,他们的功能是相似的或者说相近的 插头要使用插座,进而接通电流 现实世界到代码的转换 电源插座代码示例 港版插座面板 package adapter; /**目标角色 Target 接口 * 香港地区使用的

java 连接mariadb 无法获取数据源的问题,在ubuntu上部署的时候(原创)

问题: 连接数据库时报错: log4j:WARN No appenders could be found for logger (com.mchange.v2.log.MLog).log4j:WARN Please initialize the log4j system properly.log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.java.lang.RuntimeExcep

View(视图)——ListView概述、Adapter分类

ListView 1.概念 (1)列表视图 (2)用来显示多个可滑动项列表的ViewGroup (3)需要适配器Adapter将集合中数据和每一个Item所对应的布局动态适配到ListView中进行显示 2.适配器 Adaper (1)API (2)分类 3.监听器 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.