慕客网-Android必学-BaseAdapter的使用与优化-学习笔记
数据适配器是数据源与视图(View)之间的桥梁,建立了两者之间的适配关系。数据的来源是各种各样的,但View能显示的格式却是有一定要求的,数据适配器是把各种各样的数据源转化成为View能显示的数据格式。
优点:
将数据的来源与数据的显示进行了解耦,降低程序的耦合性,提高可扩展性。
BaseAdapter是Android各种各样适配器里最通用的适配器。
在使用BaseAdapter时,我们需要自己创建一个类继承BaseAdapter,然后Eclipse会提醒我们实现上述四个方法,当给ListView设置了我们自己写的Adapter后,ListView内部会调用上述四个方法。
这是BaseAdapter使用的基本形式,下面是实现步骤:
<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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.mybaseadapter.MainActivity" >
<ListView
android:id="@+id/lv_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</RelativeLayout>
创建单条数据项的Layout布局: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="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="@+id/iv_image"
android:layout_width="64dp"
android:layout_height="64dp"
android:src="@drawable/ic_launcher"
/>
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_toRightOf="@id/iv_image"
android:text="Title"
android:gravity="center"
android:textSize="25sp"
/>
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_toRightOf="@id/iv_image"
android:layout_below="@id/tv_title"
android:text="Content"
android:gravity="center_vertical"
android:textSize="20sp"
/>
</RelativeLayout>
package com.mybaseadapter;
public class ItemBean {
public int itemImageResid;
public String itemTitle;
public String itemContent;
public ItemBean(int itemImageResid, String itemTitle, String itemContent) {
super();
this.itemImageResid = itemImageResid;
this.itemTitle = itemTitle;
this.itemContent = itemContent;
}
}
package com.mybaseadapter;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
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 List<ItemBean> mList;
private LayoutInflater mInflater;
/**
* 关联数据源与数据适配器
* @param list
*/
public MyAdapter(Context context, List<ItemBean> list){
mList = list;
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mList.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mList.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;//对应的索引项
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
// 返回每一项的显示内容
/********* 逗比式 **************/
/**
* 无视convertView和parent,没有考虑ListView的感受,没有使用缓存机制
* 每次都是创建一个新的View, 并在View中找到相应的控件去设置相应的值,
* 完全没用到缓存机制,对资源造成了极大浪费
*/
//创建View
View view = this.mInflater.inflate(R.layout.item, null);
ImageView image = (ImageView) view.findViewById(R.id.iv_image);
TextView title = (TextView) view.findViewById(R.id.tv_title);
TextView content = (TextView) view.findViewById(R.id.tv_title);
//关联数据
image.setImageResource(mList.get(position).itemImageResid);
title.setText(mList.get(position).itemTitle);
content.setText(mList.get(position).itemContent);
return view;
}
}
package com.mybaseadapter;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.ListView;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建测试数据
List<ItemBean> itemBeanList = new ArrayList<ItemBean>();
for(int i = 0; i < 20; i++ ){
itemBeanList.add(new ItemBean(
R.drawable.ic_launcher,
"标题 " + i,
"内容 " + i
));
}
ListView lv = (ListView) findViewById(R.id.lv_main);
MyAdapter adapter = new MyAdapter(this, itemBeanList);
lv.setAdapter(adapter);
}
}
普通式是逗比式的升级版,升级的地方就是在MyAdapter的getView里,逗比式里没有使用到ListView的缓存机制,在普通式里这个缺点会被弥补。
下面是普通式的getView方法代码:
public View getView(int position, View convertView, ViewGroup parent) {
/**********普通方法***************/
if (convertView == null){ //判断convertView是否已被缓存,通过这个判断就避免创建大量的View,从而大大地节省了资源
convertView = this.mInflater.inflate(R.layout.item, null);
}
ImageView image = (ImageView) convertView.findViewById(R.id.iv_image);
TextView title = (TextView) convertView.findViewById(R.id.tv_title);
TextView content = (TextView) convertView.findViewById(R.id.tv_title);
//关联数据
image.setImageResource(mList.get(position).itemImageResid);
title.setText(mList.get(position).itemTitle);
content.setText(mList.get(position).itemContent);
return convertView;
/********************************/
}
普通式与逗比式的差别在于普通式使用的View是系统缓存的convertView,通过判断可以避免创建大量的View,从而大量的节省了资源。
但findViewById仍然会浪费大量的时间,这也是为什么这个方法只能称为普通式的原因。
在getView里面的两个耗时:
- 创建大量的View
- findViewById查找控件
我们通过普通式解决了第一个耗时操作,下面就开始着手解决第二个耗时操作。
这个方法由2013年Google开发者大会上的某个开发者提出,具体过程分为:
1. 创建ViewHolder内部类,里面包含ListView单行界面布局的所有控件变量;
2. 在getView中先准备变量viewHolder,然后判断convertView是否为空,为空则转第3步,否则转第4步;
3. 使用Inflater创建convertView,实例化viewHolder,使用findViewById实例化viewHolder里的三个控件,接下来,就是最重要的,使用setTag方法将convertView与viewHolder关联起来(具体看代码),因为convertView会被系统缓存,所以同时ViewHolder也被缓存;
4. 使用getTag方法取出viewHolder,然后用数据填充viewHolder里的控件,而不用再先使用findViewById查找控件后赋值,从而节省了大量的时间。
下面是MyAdapter类getView方法文艺式实现的代码:
public View getView(int position, View convertView, ViewGroup parent) {
/*************文艺式***************/
ViewHolder viewHolder = null;
if (convertView == null){
convertView = this.mInflater.inflate(R.layout.item, null);
viewHolder = new ViewHolder();
viewHolder.image = (ImageView) convertView.findViewById(R.id.iv_image);
viewHolder.title = (TextView) convertView.findViewById(R.id.tv_title);
viewHolder.content = (TextView) convertView.findViewById(R.id.tv_content);
//将ViewHolder与convertView进行关联
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.image.setImageResource(mList.get(position).itemImageResid);
viewHolder.title.setText(mList.get(position).itemTitle);
viewHolder.content.setText(mList.get(position).itemContent);
return convertView;
/*********************************/
}
class ViewHolder{
public ImageView image;
public TextView title;
public TextView content;
}
通过这种做法,就避免了大量的findViewById,从而大大地节省了时间。
逗比式、普通式、文艺式是循序渐进逐步优化的,我在其中可以学到了我们应该对控件的内部机制何相关设计模式有一定了解,这样才能理解那些API为什么要这样设计,这样才能做到灵活运用。另外,有时候也可尝试一下另辟蹊径,文艺式里使用setTag来缓存ViewHolder就属于此。
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/zgljl2012/article/details/47285263