大家都知道listview的格式是一定的 而数据源确是多重多样的 这时候
就需要一种适配器来把数据源转换成listview要显示的格式
baseAdapter就诞生了。
listview和gridView的显示和缓存机制
大家都知道屏幕的大小是有限的
可是listview中的数据却可能很多 所以手机不能一下子展示所有的数据 它只会加载屏幕上显示的数据 。
如上图,当我们把屏幕往下滑动时 item1回收到recycler 而item8要显示在屏幕上
item8从recycler取出这样一个布局文件 并重新设置好item8要显示的数据 并设置要要显示的位置。
总之一句话 需要才显示 显示完就被回收到缓存。在listview的适配器上
有这样一个方法
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
三种方式
下面我们通过一个实例 来比较adapter的三重境界孰强孰弱
要实现的效果如下
activity_main.xml
[html] view plain copy print?在CODE上查看代码片派生到我的代码片
<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_listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
></ListView>
</LinearLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/iv_image"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentLeft="true"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/tv_nickName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/iv_image"
android:gravity="center_horizontal"
android:textSize="20sp"
android:text="昵称" />
<TextView
android:id="@+id/tv_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/iv_image"
android:layout_below="@id/tv_nickName"
android:textSize="15sp"
android:text="内容" />
</RelativeLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
为了方便 ,我创建了一个myObject对象 用来封装item.xml要显示的数据
MyObject.class
package com.example.baseadapter;
import android.widget.ImageView;
import android.widget.TextView;
public class MyObject {
private int imageViewId;
private String nickName;
private String content;
public MyObject(int imageViewId, String nickName, String content) {
this.imageViewId = imageViewId;
this.nickName = nickName;
this.content = content;
}
public String getNickName() {
return nickName;
}
public String getContent() {
return content;
}
public int getImageViewId() {
return imageViewId;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
MainActivity.class
package com.example.baseadapter;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.ListView;
public class MainActivity extends Activity {
private List<MyObject> list=new ArrayList<MyObject>();
private ListView listView;
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView=(ListView) findViewById(R.id.lv_listView);
for(int i=0;i<50;i++){
list.add(new MyObject(R.drawable.ic_launcher, "昵称"+i, "内容"+i));
}
myAdapter=new MyAdapter(list, this);
listView.setAdapter(myAdapter);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
自定义的adapter
MyAdapter.class
package com.example.baseadapter;
import java.util.List;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class MyAdapter extends BaseAdapter {
private long sum = 0;
private List<MyObject> list;
private Context context;
public MyAdapter(List<MyObject> list, Context context) {
this.list = list;
this.context = context;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
long star = System.nanoTime();
View view=View.inflate(context, R.layout.item, null);
ImageView imageView =(ImageView) view.findViewById(R.id.iv_image);
TextView nickName=(TextView) view.findViewById(R.id.tv_nickName);
TextView content=(TextView) view.findViewById(R.id.tv_content);
MyObject myObject=list.get(position);
imageView.setBackgroundResource(myObject.getImageViewId());
nickName.setText(myObject.getNickName());
content.setText(myObject.getContent());
long end = System.nanoTime();
sum += end - star;
Log.d("main", "第一种" + sum);
return view;
}
class ViewHolder {
public ImageView imageView;
private TextView nickName;
private TextView content;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
下面我们分析一下第一种
前面已经说了,liseview具有缓存机制 可以将使用过的item放入缓冲池中,而在这里
每次调用getview方法的时候 我们都是创建新的view对象 并没有利用listview的缓存机制
没有任何处理 ,效率及其低下
而第二种 普通式是利用了getview方法中传入的contentview对象
并且加一个if判断
if (convertView == null) {
convertView = View.inflate(context, R.layout.item, null);
}
虽然只是一个if判断 但是 通过这个判断 可以避免创建大量的contentview对象 节省了大量的时间
利用了ListView的缓存特性 如果没有缓存才创建新的view 对getview方法进行了非常好的优化
但这仅仅只算入门,因为findViewById依然会浪费大量的时间 所以我们称这种方法为普通式
那么第三种境界就是对findViewById的优化了 把findViewById
也放入if判断语句中 就ok了
我们需要创建一个内部类
里面有三个成员变量 都是我们item.xml文件中的三个控件
class ViewHolder {
public ImageView imageView;
private TextView nickName;
private TextView content;
}
通过viewHolder.setTag()方法 把viewHolder和contentView关联在一起
然后通过getTag方法得到viewHolder
这种方法不仅利用了listview的缓存,更通过viewHolder来实现显示视图的缓存,避免多次使用findViewById方法
作为一个有情怀的程序员 这才是最好的写法~