Android开发专栏之ListView一两种适配器的使用和优化
来源:互联网 发布:网络直播策划案脚本 编辑:程序博客网 时间:2024/06/08 13:39
前言:
最近花了几天时间研究了下ListView的优化,然后写了一些demo,现在把这些天的东西总结。ListView的适配器主要有三种,ArrayAdapter,SimpleAdapter,SimpleCursorAdapter,我对于简单游标适配器还不了解,这里只说前两种。优化方式这里提到的主要就是converView,ViewHolder.还有加载图片的优化,这里先不涉及,我到后面会补充哦。
不同的适配器的区别主要是使用的数据结构不同,数组适配器就是使用数组,而简单适配器一般使用HashMap或者Map。
两种适配器:
1.ArrayAdapter:
数组适配器有三种使用方法
第一种: 是直接使用一个TextView作为根布局
<?xml version="1.0" encoding="utf-8"?><TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/tv_itemContent_arrayAdapter1" android:layout_width="wrap_content" android:layout_height="wrap_content" />
然后直接调用API里的ArrayAdapter就可以了:
//用这种方式来创建listView ListView mlistView=new ListView(this); String[] items={"1.ArrayAdapterData1", "2.ArrayAdapterData2", "3.ArrayAdapterData3", "4.ArrayAdapterData4"}; //创建数组适配器方式1 //参数1:context //参数2:listView的layout的id,要注意的是这个layout里面只能有一个控件就是TextView,连layout都不可以有!否则程序崩溃 //数组 ArrayAdapter<String> arrayAdapter=new ArrayAdapter<String>(this,R.layout.listview_arrayadapter_layout1,items);
Demo运行:
第二种:可以有Layout作为ListView的根布局,并且可以有几个控件,但是只能填充其中一个TextView的内容
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"><TextView android:id="@+id/tv_itemContent_arrayAdapter2" android:layout_width="wrap_content" android:layout_height="wrap_content" /><Button android:id="@+id/bt_itemButton_arrayAdapter2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="button" android:onClick="onButtonClick" /></LinearLayout>
然后这样调用:
//用这种方式来创建listView ListView mlistView=new ListView(this); String[] items={"1.ArrayAdapterData1", "2.ArrayAdapterData2", "3.ArrayAdapterData3", "4.ArrayAdapterData4"}; //创建数组适配器方式2 //参数1:context //参数2:listView的layout的id,里面有多个控件 //要填充数组数据的textView的id //数组 ArrayAdapter<String> arrayAdapter= new ArrayAdapter<String>(this,R.layout.listview_arrayadapter_layout2,R.id.tv_itemContent_arrayAdapter2,items);
demo运行:
第三种:可以自定义ArrayAdapter,因为数组适配器的内容只能是一个元素,无法填充每行有多个控件的ListView,所以只要把数组元素换成自定义的类对象就可以了,然后还要重写ArrayAdapter,因为原本的ArrayAdapter的getView()方法无法根据我们自定义的类对象来填充数据。
自定义类:
/**自定义数组适配器的item类 * Created by daniel on 15-8-14. */public class Fruit { private int imageId; private String name; public Fruit(int imageId,String name){ this.imageId=imageId; this.name=name; } public int getImageId(){ return imageId; } public void setImageId(int imageId){ this.imageId=imageId; } public String getName(){ return name; } public void setName(String name){ this.name=name; } @Override public String toString(){ return "Fruit{"+ "imageId="+this.imageId+ ",name='"+this.name+'\''+ '}'; }}
自定义的适配器类:
/**自定义的ArrayAdapter * Created by daniel on 15-8-14. */public class FruitAdapter extends ArrayAdapter<Fruit>{ private List<Fruit> list; private Context context; private int resourceId; private LayoutInflater inflater; /** * 构造方法 * @param context * @param resourceId ListView的layout的id * @param list 填充数据 */ public FruitAdapter(Context context,int resourceId,List<Fruit> list){ super(context,resourceId,list); inflater=LayoutInflater.from(context); this.context=context; this.resourceId=resourceId; this.list=list; } @Override public View getView(int position,View convertView,ViewGroup parent){ ViewHolder viewHolder=null; Fruit fruit=getItem(position); if(convertView==null){ convertView=inflater.inflate(R.layout.listview_arrayadapter_layout3,parent,false); viewHolder=new ViewHolder(); viewHolder.mitemImage=(ImageView)convertView.findViewById(R.id.iv_itemImage_arrayAdapter3); viewHolder.mitemName=(TextView)convertView.findViewById(R.id.tv_itemContent_arrayAdapter3); convertView.setTag(viewHolder); }else{ viewHolder=(ViewHolder)convertView.getTag(); } viewHolder.mitemImage.setImageResource(fruit.getImageId()); viewHolder.mitemName.setText(fruit.getName()); return convertView; } private final static class ViewHolder{ ImageView mitemImage; TextView mitemName; }}
这么调用:
private List<Fruit> mfruitList; private ListView mlistView; FruitAdapter fruitAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_list_view__array_adapter__demo2); mlistView=(ListView)findViewById(R.id.listView_arrayAdapter3); mfruitList=new ArrayList<Fruit>(); initData(); fruitAdapter=new FruitAdapter(this,R.layout.listview_arrayadapter_layout3,mfruitList); mlistView.setAdapter(fruitAdapter); mlistView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Fruit fruit=mfruitList.get(position); Toast.makeText(ListView_Extends_ArrayAdapter_Demo.this, fruit.toString(), Toast.LENGTH_SHORT).show(); } }); } /** * 填充数据到数组里 */ private void initData() { Fruit apple=new Fruit(R.drawable.ic_launcher,"苹果"); mfruitList.add(apple); Fruit waterMelon=new Fruit(R.drawable.ic_launcher,"西瓜"); mfruitList.add(waterMelon); }
demo运行:
2.SimpleAdapter:
SimpleAdapter一般使用的是HashMap,根据不同的key向不同的控件内填充内容。
<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context="com.study.daniel.gridviewtest.ListView_SimpleAdapter_Demo"><ImageView android:id="@+id/iv_itemImage_simpleAdapter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="3dp" android:src="@drawable/ic_launcher" /><TextView android:id="@+id/tv_itemName_simpleAdapter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@+id/iv_itemImage_simpleAdapter" android:layout_marginTop="5dp" android:text="itemName" /><TextView android:id="@+id/tv_itemPhone_simpleAdapter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/tv_itemName_simpleAdapter" android:layout_toRightOf="@+id/iv_itemImage_simpleAdapter" android:layout_alignBaseline="@+id/iv_itemImage_simpleAdapter" android:text="itemPhone" /><TextView android:id="@+id/tv_itemRegion_simpleAdapter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@+id/tv_itemPhone_simpleAdapter" android:layout_alignBaseline="@+id/tv_itemPhone_simpleAdapter" android:layout_marginLeft="10dip" android:text="itemRegion" /></RelativeLayout>
调用:
private String[] itemNames={"Mr 1","Mr 2","Mr 3","Mr 4" ,"Miss 5"}; private String[] itemPhones={"000","001","002","003","004"}; private String[] itemRegions={"纽约","东京","哥伦比亚","安徽","未知"}; private ArrayList<Map<String,Object>> mInfos=new ArrayList<Map<String,Object>>(); private ListView mlistView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // setContentView(R.layout.listview_simpleadapter_layout); //数据填充 for(int i=0;i<itemNames.length;i++){ Map<String,Object> item=new HashMap<String,Object>(); item.put("itemName",itemNames[i]); item.put("itemPhone",itemPhones[i]); item.put("itemRegion",itemRegions[i]); item.put("itemImage",R.drawable.ic_launcher); mInfos.add(item); } mlistView=new ListView(this); SimpleAdapter simpleAdapter=new SimpleAdapter(this,mInfos,R.layout.listview_simpleadapter_layout, new String[]{"itemName","itemPhone","itemRegion","itemImage"}, new int[]{R.id.tv_itemName_simpleAdapter,R.id.tv_itemPhone_simpleAdapter,R.id.tv_itemRegion_simpleAdapter,R.id.iv_itemImage_simpleAdapter} ); mlistView.setAdapter(simpleAdapter); setContentView(mlistView);}
demo运行如下:
优化:
关于优化主要就是两步,(这个理解起来要花一些时间,我研究了三天才搞懂)一个是防止每次都将ListView的每一行的布局文件实例化,所以在向上翻动的时候重用第一页的布局对象,及getView的convertView参数。但是这只是重用了布局文件,防止了布局文件实例化的IO操作,ListView每一行可能有很多控件,比如Button,TextView,ImageView等,这些控件从xml文件里面读取并且实例化成对象也是非常耗费内存的,所以也得重用,可以使用ViewHolder,这个类的对象中将保存listView每一行的控件为成员变量,然后用setTag和这个convertView绑定在一起,其实看下源码就是保存这个Object对象在convertView里面了,方便下次取出。然后每次getView的时候只要给ViewHolder的里面的成员变量设置显示内容就可以了。因为这些子布局的控件已经变成viewHolder对象的成员变量了,设定它们的内容就是设定控件的内容。
另外,如果ListView不同的行具有不同的子布局的话,就需要不同的ViewHolder了,有几种布局就需要几种viewHolder,因为保存的控件不同了,然后重写两个函数getViewTypeCount,getViewType,在getView里面显式调用getViewType方法,在选择不同的viewHolder时候加一个switch判断就好了。代码这里就不展示,代码会上传,大家自行下载。
demo运行:
只有一种布局的优化demo:
多种布局的优化demo:
非常容易犯错的问题:
在写多种布局的优化demo时候,程序总是崩溃,调bug都调不出来,后来找了整整一天,才发现是因为布局种类的type下标必须从0开始!!如果从1开始,就会造成程序崩溃!
代码上传:
1.ArrayAdapter使用方式1,2的demo:
http://download.csdn.net/detail/u012320459/9007389
2.ArrayAdapter使用方式3(自定义)的demo:
http://download.csdn.net/detail/u012320459/9007423
3.SimpleAdapter使用demo:
http://download.csdn.net/detail/u012320459/9007463
4.扩展自BaseAdapter的适配器的单一布局的优化demo:
http://download.csdn.net/detail/u012320459/9007469
5.扩展自BaseAdapter的适配器的多种布局的优化demo:
http://download.csdn.net/detail/u012320459/9007655
- Android开发专栏之ListView一两种适配器的使用和优化
- Android开发之ListView适配器优化
- Android-ListView适配器BaseAdapter的使用和优化
- [ListView]Android开发之ListView 适配器(Adapter)优化
- [ListView]Android开发之ListView 适配器(Adapter)优化
- Android开发ListView适配器优化
- Android 开发ListView适配器优化
- Android开发之ListView 适配器(Adapter)优化
- Android开发之ListView 适配器(Adapter)优化
- Android开发之ListView 适配器(Adapter)优化
- Android开发之ListView 适配器(Adapter)优化
- Android开发之ListView 适配器(Adapter)优化
- Android开发之ListView 适配器(Adapter)优化
- Android开发之ListView 适配器(Adapter)优化
- Android开发之ListView 适配器(Adapter)优化
- Android开发之ListView 适配器(Adapter)优化
- Android开发之ListView 适配器(Adapter)优化
- Android开发之ListView 适配器(Adapter)优化
- Genealogical tree 2367 (拓扑排序)
- P1040 高精度乘法
- GUI
- HDU1285确定比赛名次【拓扑排序】
- C++对象模型——对象复制语意学 (Object Copy Semantics)(第五章)
- Android开发专栏之ListView一两种适配器的使用和优化
- 【python】python新手必碰到的问题---encode与decode,中文乱码[转]
- 高仿知乎日报(三)
- test
- Labeling Balls 3687(拓扑排序+反向建图)
- javascript高级程序设计知识整理(3)
- 字符串连接(strcat)的函数
- 默认函数实现全排列
- HDU1158 Employment Planning