对于ListVie来说,数据项的设置有很多种方式,而自定义实现BaseAdapter是最经常用的了,那么这里我们来讲解一下自定义实现BaseAdapter的普通实现。
MainActivity.java
public class MainActivity extends AppCompatActivity {
//数据源
private List<String> data;
//ListView控件
private ListView mList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取控件ID
mList = (ListView)findViewById(R.id.mList);
data = new ArrayList<>();
//数据赋初值
for(int i = 0; i < 20; i ++){
data.add("数据项"+ i);
}
//创建适配器
MyAdapter adapter = new MyAdapter(data);
//设置适配器
mList.setAdapter(adapter);
}
}
MyAdapter.java
public class MyAdapter extends BaseAdapter {
//数据项
private List<String> data;
public MyAdapter(List<String> data) {
this.data = data;
}
@Override
/**
* 返回数据源的长度,表示ListView的item项显示多少个
*/
public int getCount() {
return data == null ? 0 : data.size();
}
/**
* 返回指定位置的 item 数据源的对象,这个方法为手动调用,非设置适配器时候调用
* @param position 指定位置
* @return
*/
@Override
public Object getItem(int position) {
return data.get(position);
}
/**
* 返回指定位置的 item的标记 id,很少使用到
* @param position 指定位置
* @return
*/
@Override
public long getItemId(int position) {
return position;
}
/**
* 工厂方法,设置好模板,返回视图,每个视图是怎么显示出来的, 核心点,怎么产生一个View, View 里面怎么
* 放置对应的内容
* @param position 当前加载的位置
* @param convertView 复用的view
* @param parent listview
* @return
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//获取布局
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item,null);
//获取布局中的TextView控件1
TextView tv1 = (TextView) view.findViewById(R.id.mTv1);
//设置控件1的数据
tv1.setText(data.get(position));
//获取布局中的TextView控件2
TextView tv2 = (TextView) view.findViewById(R.id.mTv2);
//设置控件2数据
tv2.setText(data.get(position));
return view;
}
}
以上是普通的使用,但是这样的效率会非常低,因为每次加载一个item都会调用getView方法,而每次都会去解析一个view布局,这样一直解析会对内存的消耗特别大,所以效率会大大降低,那么我们在此基础上先稍微优化下,让view解析次数变少一点,最基本的操作就是采用convertView复用控件来进行操作。
这里只需要修改getView方法中的处理:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.i("TAG", "getView: " + position);
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, null);
}
TextView tv1 = (TextView) convertView.findViewById(R.id.mTv1);
tv1.setText(data.get(position));
TextView tv2 = (TextView) convertView.findViewById(R.id.mTv2);
tv2.setText(data.get(position));
return convertView;
}
}
以上的处理方式相比上面的处理方式相对于上面的解析要少很多次,因为第一种实现方式是任何一个需要显示的控件都需要去解析一次布局,而这里我们使用了系统给的converView复用控件,他的基本原理是,系统会自动创建好界面显示n个item的数据项(比如一个界面可见的item为5个,默认创建好了5个view布局对象),保存到converView中(这里可以把他当成一个循环数组吧,他的总容量相当于是n + 1),当显示第n + 1个的时候,他会解析一次,之后的显示的view布局会复用自己的converView中已经存在的布局项,而不再去重新解析。简单的画个图吧:
如上图所示,相当于只解析了6次,其他的view都是复用的,所以相对于上面的实现,这样的效率会相对高一点,不过,虽然解析的次数是少了,但是每个控件需要findViewById还是会重复调用,而且其实每个不同对象view中的控件id对象肯定是相同的,所以,重复的去调用又会显得效率不高,那么如何解决不重复findViewById呢,那就要使用到我们的优化布局了,关于优化,将在下一篇博客中介绍。