android中 List、Map简单介绍及ArrayAdapter、SimpleAdapter、BaseAdapter简单总结

时间:2021-08-29 19:11:05

~~~~我的生活,我的点点滴滴!!



List(列表): 



List的特征是其元素以线性方式存储,集合中可以存放重复的对象,他是一个接口类,他的主要实现类包括ArrayList、LinkedList、Stack、Vector

我们说说常用三个:

1、ArrayList: 代表长度是可以改变的数组,可以对元素进行随机的访问,向ArrayList()中插入与删除元素的速度慢。他只适合随机查找、遍历,快速访问等。

2、Vector: 也是通过数组实现的,他和ArrayList基本一样的,唯一的区别是他支持线程的同步,即某一时刻只有一个线程能写Vector(自带加锁与解锁功能),

但是线程同步是需要代价的,因此他访问比ArrayList要慢。

3、LinkedList: 在实现中采用链表数据结构,插入和删除速度快,访问速度慢,另外他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,

可以当作堆栈、队列和双向队列使用。

注意:对于Vector与ArrayList,当发现数组的大小不够用的时候,需要重新建立数组,然后将元素拷贝到新的数组内,所以他们的代价还是蛮大的,默认他们
的扩展空间如下:

a、ArrayList在内存不足时默认扩大50%+1个。

b、Vector默认扩大100%即1倍。

但是对于Stack,看源码就知道他不属于List的直接实现类,所以对于Stack可以直接使用 Stack stack = new Stack();

所以对于List的对象,我们的new的时候,要选择使用上面两种中的一种来生成相应的容器。

例如:

List<String> listItems = new ArrayList<String>();

对List的的随机访问来说,就是只随机来检索位于特定位置的元素,List的get(int index)方法获取集合中index参数的位置对象,下标是从0开始的,

最基本的两种检索集合中的所有对象的方法:


1、for+get方法

for(int i = 0; i < list.size(); ++ i)
{
System.out.println(list.get(i));
}


2、Iterator迭代器

Iterator it = list.iterator();


while( it.hashNext )
{
System.out.println(it.next);
}


ps:具体的函数接口及使用方法可以看源码或帮助文档。



Map(映射):



Map 是一种把健对象和值对象映射的集合,它的每一个元素都包括一对健对象和值对象,他是接口类,常用的实现类有HashMap、TreeMap、LinkedHashMap:


HashMap:基于散列表的实现,插入与查询的开销是常量级,操作很快。


LinkedHashMap: 类似于HashMap,他在迭代遍历时,取得键值对的顺序是他插入时的顺序,比HashMap要慢一点。


TreeMap:基于红黑树实现的,这个才是对应于C++ STL中的Map,TreeMap是默认根根据键值排序的,速度快。


简单的介绍就到此为止,因为我主要是想知道和C++ 中的一些区别与熟悉一下java中的容器,详细介绍和使用样例见下面的链接:


http://www.cnblogs.com/littlehann/p/3690187.html


相当全面。




SimpleAdapter



SimpleAdapter是一个简单的适配器,可以将静态数据映射到XML文件中定义好的视图。


SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)


参数说明:


context: SimpleAdapter关联的View的运行对象


data: 一个Map组成的List数据结构,在列表中的每个条目对应列表中的一行,每一个Map中应该包含所有在from参数中指定的键(Key)


resource: 一个定义列表项的布局文件的资源ID,布局文件将至少包含那些在to中定义的ID


from: 一个将被添加到Map映射上的键名(key)


to: 将绑定数据的视图的ID(map中的value),跟from对数对应,并且应该是view


在ListView中使用样例:


List< Map<String, Object> > listItems = new ArrayList< Map<String, Object> >();

for( int i = 0; i < files.length; ++ i )
{
Map<String, Object> itemMap = new HashMap<String, Object>();

if( files[i].isDirectory() )
{
itemMap.put("icon", R.drawable.folder);
}
else if( files[i].isFile() )
{
itemMap.put("icon", R.drawable.file);
}
itemMap.put("fileName", files[i].getName());
listItems.add(itemMap);
}


SimpleAdapter simpleAdapter = new SimpleAdapter(this, listItems, R.layout.line,
new String[]{"icon", "fileName"}, new int[]{R.id.icon, R.id.file_name});


listView.setAdapter(simpleAdapter);


new String[]{"icon", "fileName"} 是 构造函数中的 from 他表示了我的map里面键值对key只有icon、fileName这两个key
new int[]{R.id.icon, R.id.file_name} 是 构造函数中的 to 他表示了我map里面键值对value的资源ID
R.layout.line 是 构造函数中的 resource 他表示一个资源文件
内容如下:

line.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="match_parent"
android:orientation="horizontal" >


<ImageView
android:id="@+id/icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:paddingLeft="10dp"
android:src="@drawable/abc_ab_bottom_solid_dark_holo" />


<TextView
android:id="@+id/file_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingBottom="10dp"
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:textSize="16dp" />


</LinearLayout>


里面要包括from和to里面的内容。




ArrayAdapter


ArrayAdapter 数组适配器,一般用于显示一行文本信息,相对比较简单,默认的ArrayAdapter期望接受的样式文件只含有一个textview,然后它把

接受到的数据toString显示出来,但是他有6个构造函数(够多的呀),我们挑几个复杂常用点的介绍:

ArrayAdapter(Context context, int resource)
ArrayAdapter(Context context, int resource, int textViewResourceId)


之所以把上面两个构造函数放一起说,是因为其实他们可以当成一体的,看下面例子:

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_expandable_list_item_1);
adapter.add("string1");
adapter.add("haha");
adapter.add("heihei");
listview.setAdapter(adapter);

android.R.layout.simple_expandable_list_item_1为android自己提供的样式,
当然我们可以换成我们自己的样式,看下面:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"  
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/online_user_list_item_textview" >
</TextView>

有没有发觉这个xml文件有什么不同?是的,他没有布局,如果使用上面的ArrayAdapter(Context context, int resource)构造函数,那么对应的xml资

文件仅只能有一个TextView,那么我们非要使用多个控件,还要使用布局怎么办?使用上面第二个构造函数,他的第三个参数就是用来指定TextView

的,下面布局文件:


<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/online_user_list_item_textview"
android:text="TextView"></TextView>
<Button
android:text="button"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Button>


</LinearLayout>


里面含有的textview是我们想要显示内容的地方,那么我们改成下面代码就好了


ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.online_user_list_item, 
R.id.online_user_list_item_textview);



简单的构造函数介绍完了,看看稍微复杂点的。

ArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects)


ArrayAdapter(Context context, int resource, List<T> objects)


context:关联的对象


resource:资源文件ID


List: 一个list对象


上面这两个构造函数和最开始的介绍的一样,相差无异,只是多了一个textviewid,这样就意味着可以使用复杂的资源xml文件,只需要告诉
textview的id就ok了,看下面的例子。


我们在一个布局xml资源中放置一个ImageView,一个TextView,内容如下:


list_item.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="match_parent"
android:orientation="horizontal" >


<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"
/>
<TextView
android:id="@+id/tv"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>


</LinearLayout>


使用代码只需要更改成如下:

private ArrayList<String> list = new ArrayList<String>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
lv = (ListView)findViewById(R.id.listview);


ArrayAdapter<String> adapter = new ArrayAdapter<String>(
this,
R.layout.list_item,
R.id.tv,
getData());
lv.setAdapter(adapter);
}


private ArrayList<String> getData()
{
list.add("180平米的房子");
list.add("一个勤劳漂亮的老婆");
list.add("一辆宝马");
list.add("一个强壮且永不生病的身体");
list.add("一个喜欢的事业");
return list;
}


这样就实现一个带上图片+文字的list列表了,效果看上去和SimpleAdapter差不多,但是不如SimpleAdapter灵活。如果要实现更复杂的效果就要

重载ArrayAdapter中的getView()函数了,这里不给出来,请看下面链接:
http://blog.csdn.net/nairuohe/article/details/6457300
http://www.cnblogs.com/sayo/archive/2010/12/30/1922590.html
http://www.cnblogs.com/xirihanlin/archive/2009/08/03/1537609.html
http://blog.csdn.net/andie_guo/article/details/12554321 此链接重写实现了AutoComplete功能



那还不如直接使用BaseAdapter,全部重写,下面就来看看BaseAdapter



BaseAdapter



它是直接继承自接口类Adapter的,使用BaseAdapter时需要重写很多方法,其中最重要的当属getView,但是这会涉及到ListView优化等问题了。


使用BaseAdapter就需要继承他,然后重写里面的许多方法。


class MyAdapter extends BaseAdapter
{
private Context context;
public MyAdapter(Context context)
{
this.context = context;
}
@Override
public int getCount() {
// How many items are in the data set represented by this Adapter.(在此适配器中所代表的数据集中的条目数)
return 0;
}


@Override
public Object getItem(int position) {
// Get the data item associated with the specified position in the data set.(获取数据集中与指定索引对应的数据项)
return null;
}


@Override
public long getItemId(int position) {
// Get the row id associated with the specified position in the list.(取在列表中与指定索引对应的行id)
return 0;
}


@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get a View that displays the data at the specified position in the data set.
return null;
}

}



这里面没什么难度,但是这个getView方法必须好好处理,也是最麻烦的


第一种:没有任何处理,不建议这样写。如果数据量少还可以凑合,但是如果列表项数据量很大的时候,会每次都重新创建View,设置资源,严重影响性

能,所以从一开始就不要用这种方式:



@Override
public View getView(int position, View convertView, ViewGroup parent)
{
View item = mInflater.inflate(R.layout.list_item, null);
ImageView img = (ImageView)item.findViewById(R.id.img)
TextView title = (TextView)item.findViewById(R.id.title);
TextView info = (TextView)item.findViewById(R.id.info);
img.setImageResource(R.drawable.ic_launcher);
title.setText("Hello");
info.setText("world");

return item;
}



第二种ListView优化:通过缓存convertView,这种利用缓存contentView的方式可以判断如果缓存中不存在View才创建View,如果已经存在可以利用缓存中

的View,提升了性能:



public View getView(int position, View convertView, ViewGroup parent) 
{
//重点在这里面
if(convertView == null)
{
convertView = mInflater.inflate(R.layout.list_item, null);
}

ImageView img = (ImageView)convertView.findViewById(R.id.img)
TextView title = (TextView)convertView.findViewById(R.id.title);
TextView info = (TextView)ConvertView.findViewById(R.id.info);
img.setImageResource(R.drawable.ic_launcher);
title.setText("Hello");
info.setText("world");

return convertView;
}



第三种ListView优化:通过convertView+ViewHolder来实现,ViewHolder就是一个静态类,使用ViewHolder 的关键好处是缓存了显示数据的视图

(View),加快了 UI 的响应速度。



当我们判断 convertView == null  的时候,如果为空,就会根据设计好的List的Item布局(XML),来为convertView赋值,并生成一个viewHolder来绑

定converView里面的各个View控件(XML布局里面的那些控件)。再用convertView的setTag将viewHolder设置到Tag中,以便系统第二次绘制ListView时

从Tag中取出。(看下面代码中)


如果convertView不为空的时候,就会直接用convertView的getTag(),来获得一个ViewHolder。


//在外面先定义,ViewHolder静态类
static class ViewHolder
{
public ImageView img;
public TextView title;
public TextView info;
}
//然后重写getView
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
if(convertView == null)
{
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.list_item, null);
holder.img = (ImageView)item.findViewById(R.id.img)
holder.title = (TextView)item.findViewById(R.id.title);
holder.info = (TextView)item.findViewById(R.id.info);
convertView.setTag(holder);
}else
{
holder = (ViewHolder)convertView.getTag();
holder.img.setImageResource(R.drawable.ic_launcher);
holder.title.setText("Hello");
holder.info.setText("World");
}

return convertView;
}



到这里,可能会有人问ViewHolder静态类结合缓存convertView与直接使用convertView有什么区别吗,是否重复了


在这里,官方给出了解释


提升Adapter的两种方法:


To work efficiently the adapter implemented here uses two techniques:
-It reuses the convertView passed to getView() to avoid inflating View when it is not necessary


(译:重用缓存convertView传递给getView()方法来避免填充不必要的视图)
-It uses the ViewHolder pattern to avoid calling findViewById() when it is not necessary


(译:使用ViewHolder模式来避免没有必要的调用findViewById():因为太多的findViewById也会影响性能)
ViewHolder类的作用
-The ViewHolder pattern consists in storing a data structure in the tag of the view
returned by getView().This data structures contains references to the views we want to bind data to,
thus avoiding calling to findViewById() every time getView() is invoked


(译:ViewHolder模式通过getView()方法返回的视图的标签(Tag)中存储一个数据结构,这个数据结构包含了指向我们


要绑定数据的视图的引用,从而避免每次调用getView()的时候调用findViewById())


实例:用BaseAdapter来自定义ListView布局


main.xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >


<ListView
android:id="@+id/lv"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:fastScrollEnabled="true"
/>


</LinearLayout>


list_item.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="match_parent"
android:orientation="horizontal" >


<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
/>
<TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
/>
</LinearLayout>



</LinearLayout>



MainActivity.java文件


package com.example.demo;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;


public class MainActivity extends Activity
{
private ListView lv;
private List<Map<String, Object>> data;


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
lv = (ListView)findViewById(R.id.lv);
//获取将要绑定的数据设置到data中
data = getData();
MyAdapter adapter = new MyAdapter(this);
lv.setAdapter(adapter);
}

private List<Map<String, Object>> getData()
{
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
Map<String, Object> map;
for(int i=0;i<10;i++)
{
map = new HashMap<String, Object>();
map.put("img", R.drawable.ic_launcher);
map.put("title", "跆拳道");
map.put("info", "快乐源于生活...");
list.add(map);
}
return list;
}

//ViewHolder静态类
static class ViewHolder
{
public ImageView img;
public TextView title;
public TextView info;
}

//或者直接使用类似这样的代码布局
/*
BaseAdapter baseAdapter = new BaseAdapter() {


//里面各种override函数


}
*/


//或者使用这种
public class MyAdapter extends BaseAdapter
{
private LayoutInflater mInflater = null;
private MyAdapter(Context context)
{
//根据context上下文加载布局,这里的是Demo17Activity本身,即this
this.mInflater = LayoutInflater.from(context);
}


@Override
public int getCount() {
//How many items are in the data set represented by this Adapter.
//在此适配器中所代表的数据集中的条目数
return data.size();
}


@Override
public Object getItem(int position) {
// Get the data item associated with the specified position in the data set.
//获取数据集中与指定索引对应的数据项
return position;
}


@Override
public long getItemId(int position) {
//Get the row id associated with the specified position in the list.
//获取在列表中与指定索引对应的行id
return position;
}

//Get a View that displays the data at the specified position in the data set.
//获取一个在数据集中指定索引的视图来显示数据
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
//如果缓存convertView为空,则需要创建View
if(convertView == null)
{
holder = new ViewHolder();
//根据自定义的Item布局加载布局
convertView = mInflater.inflate(R.layout.list_item, null);
holder.img = (ImageView)convertView.findViewById(R.id.img);
holder.title = (TextView)convertView.findViewById(R.id.tv);
holder.info = (TextView)convertView.findViewById(R.id.info);
//将设置好的布局保存到缓存中,并将其设置在Tag里,以便后面方便取出Tag
convertView.setTag(holder);
}else
{
holder = (ViewHolder)convertView.getTag();
}
holder.img.setBackgroundResource((Integer)data.get(position).get("img"));
holder.title.setText((String)data.get(position).get("title"));
holder.info.setText((String)data.get(position).get("info"));

return convertView;
}

}
}


推荐链接: http://www.cnblogs.com/over140/archive/2010/12/03/1895128.html


最后写了这么多,还是上一个图吧,不看图光看代码,脑袋也是晕的,看下上面代码展现出来的效果图:


android中 List、Map简单介绍及ArrayAdapter、SimpleAdapter、BaseAdapter简单总结