Android之listview && adapter

时间:2022-04-16 20:39:31

  今天我们讲的也是非常重要的一个控件listview—最常用也是最难的

一个ListView通常有两个职责

(1)将数据填充到布局。

(2)处理用户的选择点击等操作。

  第一点很好理解,ListView就是实现这个功能的。第二点也不难做到,在后面的学习中读者会发现,这非常简单。

一个ListView的创建需要3个元素

(1)ListView中的每一列的View。

(2)填入View的数据或者图片等。

(3)连接数据与ListView的适配器。

也就是说,要使用ListView,首先要了解什么是适配器。适配器是一个连接数据和AdapterView(ListView就是一个典型的AdapterView,后面还会学习其他的)的桥梁,通过它能有效地实现数据与AdapterView的分离设置,使AdapterView与数据的绑定更加简便,修改更加方便

Android中提供了很多的Adapter,表4-5列出了常用的几个。

表4-5 常用适配器

Adapter

含义

ArrayAdapter<T>

用来绑定一个数组,支持泛型操作

SimpleAdapter

用来绑定在xml中定义的控件对应的数据

SimpleCursorAdapter

用来绑定游标得到的数据

BaseAdapter

通用的基础适配器

其实适配器还有很多,要注意的是,各种Adapter只不过是转换的方式和能力不一样而已。

ListView使用SimpleAdapter

很多时候需要在列表中展示一些除了文字以外的东西,比如图片等。这时候可以使用SimpleAdapter。SimpleAdapter的使用也非常简单,同时它的功能也非常强大。可以通过它自定义ListView中的item的内容,比如图片、多选框等。

使用simpleAdapter的数据一般都是用HashMap构成的列表,列表的每一节对应ListView的每一行。通过SimpleAdapter的构造函数,将HashMap的每个键的数据映射到布局文件中对应控件上。这个布局文件一般根据自己的需要来自己定义。梳理一下使用SimpleAdapter的步骤。

(1)根据需要定义ListView每行所实现的布局。

(2)定义一个HashMap构成的列表,将数据以键值对的方式存放在里面。

(3)构造SimpleAdapter对象。

(4)将LsitView绑定到SimpleAdapter上。

BaseAdapter

  在ListView的使用中,有时候还需要在里面加入按钮等控件,实现单独的操作。也就是说,这个ListView不再只是展示数据,也不仅仅是这一行要来处理用户的操作,而是里面的控件要获得用户的焦点。读者可以试试用SimpleAdapter添加一个按钮到ListView的条目中,会发现可以添加,但是却无法获得焦点,点击操作被ListView的Item所覆盖。这时候最方便的方法就是使用灵活的适配器BaseAdapter了。

  当系统开始绘制ListView的时候,首先调用getCount()方法。得到它的返回值,即ListView的长度。然后系统调用getView()方法,根据这个长度逐一绘制ListView的每一行。也就是说,如果让getCount()返回1,那么只显示一行。而getItem()和getItemId()则在需要处理和取得Adapter中的数据时调用。那么getView如何使用呢?如果有10000行数据,就绘制10000次?这肯定会极大的消耗资源,导致ListView滑动非常的慢,那应该怎么做呢?

下面就通过微信的例子说明吧!

下面是布局文件

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView> </LinearLayout>

listview_layout.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_horizontal_margin"
android:orientation="horizontal" > <ImageView
android:id="@+id/face"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/houzi" /> <LinearLayout
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:orientation="vertical" > <LinearLayout
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:orientation="horizontal" > <TextView
android:layout_weight="1"
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#7F7F7F"/> <TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textColor="#A9A9A9"/>
</LinearLayout>
<LinearLayout
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:orientation="horizontal" >
<TextView
android:layout_weight="1"
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textColor="#A9A9A9"/>
<TextView
android:id="@+id/noRead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:text=""
android:textColor="#FF0000"/>
</LinearLayout>
</LinearLayout> </LinearLayout>

middle2.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.main.weixin.MainActivity" > <!-- 头部 -->
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
> <include layout="@layout/head"/> </LinearLayout> <!-- 中间 -->
<LinearLayout
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"> <include layout = "@layout/listview_layout"></include> </LinearLayout> <!-- 尾部 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
> <include layout="@layout/bottom"/> </LinearLayout>
</LinearLayout>

activity_main.xml

下面是activity主要文件

 package com.weixin.entity;

 public class Messages {

     private String face;
private String name;
private String Date;
private String content;
private Integer noRead; public String getFace() {
return face;
}
public void setFace(String face) {
this.face = face;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDate() {
return Date;
}
public void setDate(String date) {
Date = date;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getNoRead() {
return noRead;
}
public void setNoRead(Integer noRead) {
this.noRead = noRead;
} }

Message

 package com.main.weixin;

 import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import com.database.weixin.MyDatabaseOpenHelper;
import com.weixin.entity.Messages; import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView; public class MainActivity extends Activity { private SimpleAdapter sa;
private BaseAdapter ba;
private ListView lv;
private List<Messages> listMessage = new ArrayList<Messages>();
private List<Map<String,Object>> listMessage2 = new ArrayList<Map<String,Object>>(); @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main); //模拟读取数据库或者互联网
for(int i=0 ; i<100 ; i++){
Messages message = new Messages();
message.setFace("houzi");
message.setName("孙行者"+i);
message.setDate("昨天");
message.setContent("有空吗?今晚一起吃饭");
message.setNoRead(i);
listMessage.add(message);//方法一 /* //定义一个界面与数据混合体,一个Item代表一行记录
Map<String,Object> item = new HashMap<String,Object>();
//一行多个空件
item.put("face", R.drawable.houzi);
item.put("name", "孙行者"+i);
item.put("date", "昨天");
item.put("content", "有空吗?今晚一起吃饭");
listMessage2.add(item);*/ } lv = (ListView) findViewById(R.id.listView1); /* sa = new SimpleAdapter(this,
listMessage2, //data 不仅是数据,而是数据与界面高耦合的混合体
R.layout.middle1,
new String[]{"face","name","date","content"},
new int[]{R.id.face,R.id.name,R.id.date,R.id.content}); lv.setAdapter(sa); //添加事件
lv.setOnItemClickListener(new OnItemClickListener(){ @Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) { Map<String,Object> item =listMessage2.get(position);
item.put("name", "行者孙"+position);
sa.notifyDataSetChanged();
} }); */ //简单理解为VC绑在一起
ba = new BaseAdapter(){ //返回记录数目
@Override
public int getCount() { return listMessage.size(); } //每一个item项,返回一次界面
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view ; //布局不变,数据变 //如果缓存为空,我们生成新的布局作为1个item
if(convertView == null){
Log.i("info:", "没有缓存,重新生成"+position);
LayoutInflater inflater = MainActivity.this.getLayoutInflater(); //因为getView()返回的对象,adapter会自动赋给ListView
view = inflater.inflate(R.layout.middle2, null); }else{
Log.i("info:", "有缓存,不需要重新生成"+position);
view = convertView; } Messages m = listMessage.get(position);
Integer noRead = m.getNoRead(); TextView tv_name = (TextView) view.findViewById(R.id.name);
tv_name.setText(m.getName()); TextView tv_date = (TextView) view.findViewById(R.id.date);
tv_date.setText(m.getDate()); TextView tv_content = (TextView) view.findViewById(R.id.content);
tv_content.setText(m.getContent()); System.out.println(noRead); if( noRead !=0){
TextView tv_noRead = (TextView) view.findViewById(R.id.noRead);
//这里的setText()方法接收的是一个字符串类型,而你给了一个Integer类型给它,所以报错了,这里需要把Integer类型转为String类型即可
tv_noRead.setText(noRead.toString()); } return view ; } @Override
public Object getItem(int position) {
return null;
} @Override
public long getItemId(int position) {
return 0;
} };
lv.setAdapter(ba); //添加事件
lv.setOnItemClickListener(new OnItemClickListener(){ @Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Messages message = listMessage.get(position);
if(message.getNoRead()!=0){ message.setName("行者孙"+position);
message.setNoRead(0); view.findViewById(R.id.noRead).setVisibility(View.INVISIBLE); }else{
message.setName("孙行者"+position);
} ba.notifyDataSetChanged();//
} });
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

效果如下:

Android之listview && adapter

convertView相当于一个缓存,开始为0,当有条目变为不可见,它缓存了它的数据,后面再出来的条目只需要更新数据就可以了,这样大大节省了系统资料的开销。