BaseAdapter是一个数据适配器,将我们提供的数据格式化为ListView可以显示的数据,BaseAdapter的优化直接影响到ListView的显示效率。

我们都知道,ListView自带有回收机制,当一个Item滑出屏幕的时候,ListView会自动把这个ListView回收到缓冲区,当有一个Item滑入屏幕的时候,ListView会自动从缓冲区读取一个Item,并给它赋上值,然后显示出来,这便是ListView的回收机制,然而,如果你在BaseAdapter中没有做相应的优化,你的程序有可能根本就没有使用ListView的回收机制,这将会造成很大的资源浪费。好了,下来我们看看BaseAdater的优化问题。


  • 第一步:新建项目并且准备数据

    1.新建一个android项目,修改主布局文件:

<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"
tools:context="com.example.baseadapter.MainActivity" >
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/listview"
></ListView>
</RelativeLayout>

2.在MainActivity中对数据进行初始化:

public class MainActivity extends Activity {

    private ListView listView;
private List<Person> list; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) this.findViewById(R.id.listview);
initData();
MyAdapter adapter = new MyAdapter(this,list);
listView.setAdapter(adapter);
} private void initData() {
list = new ArrayList<Person>();
Person p = null;
for (int i = 0; i < 100; i++) {
p = new Person("zhangsan" + i, i, "张三" + i);
list.add(p);
}
}
}

由于我们把Adapter单独抽取成了一个类,因此要通过构造方法来传递上下文和数据两个参数。

再来一个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="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<TextView
android:id="@+id/nickname"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
<TextView
android:id="@+id/age"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/> </LinearLayout>

  • 第二步:简单的使用

    先来看看最简单的用法,即我们不使用ListView的回收机制,也不做任何优化,看看显示效果,前面三个方法和我们平时用的时候都是一样的,不做过多说明,重点是getView方法,在getView方法中,我们每次都重新获得一个新的view,很明显,这种方式简单粗暴,效率低下,而且除了getView方法中的position参数之外,其他的参数我们都没有用到。
    @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) {
//简单使用
View v = new View(context);
TextView username = (TextView) v.findViewById(R.id.username);
TextView nickname = (TextView) v.findViewById(R.id.nickname);
TextView age = (TextView) v.findViewById(R.id.age);
username.setText(list.get(position).getUsername());
nickname.setText(list.get(position).getNickname());
age.setText(list.get(position).getAge()+"");
return v;
}

  • 第三步:使用回收机制

    上面一种方式没有使用任何的回收策略,现在我们就来解决这个问题,看看怎么使用ListView中的回收机制。这里,我们在每次使用View之前都先判断view是否为空,为空的话我们再重新获得一个View,否则就使用之前的view.
    @Override
public View getView(int position, View convertView, ViewGroup parent) {
// 简单使用
// View v = LayoutInflater.from(context).inflate(R.layout.item, null);
// TextView username = (TextView) v.findViewById(R.id.username);
// TextView nickname = (TextView) v.findViewById(R.id.nickname);
// TextView age = (TextView) v.findViewById(R.id.age);
// username.setText(list.get(position).getUsername());
// nickname.setText(list.get(position).getNickname());
// age.setText(list.get(position).getAge()+""); // 使用ListView回收机制
if (convertView == null)
convertView = LayoutInflater.from(context).inflate(R.layout.item,
null);
TextView username = (TextView) convertView.findViewById(R.id.username);
TextView nickname = (TextView) convertView.findViewById(R.id.nickname);
TextView age = (TextView) convertView.findViewById(R.id.age);
username.setText(list.get(position).getUsername());
nickname.setText(list.get(position).getNickname());
age.setText(list.get(position).getAge()+"");
return convertView;
}

  • 第四步:减少findViewById的使用

上面已经解决了回收item的问题,但是每次都要findViewById依然是非常耗时,所以这里我们将要使用一个ViewHolder来解决这个问题。所有item中的控件我们都在ViewHolder这个类中来说明,然后在实例化convertView的时候把ViewHolder保存在convertView中,在后面的使用中直接从convertView中获得ViewHolder。这样就避免了每次findViewById,尽量节省显示时间。

    @Override
public View getView(int position, View convertView, ViewGroup parent) {
// 简单使用
// View v = LayoutInflater.from(context).inflate(R.layout.item, null);
// TextView username = (TextView) v.findViewById(R.id.username);
// TextView nickname = (TextView) v.findViewById(R.id.nickname);
// TextView age = (TextView) v.findViewById(R.id.age);
// username.setText(list.get(position).getUsername());
// nickname.setText(list.get(position).getNickname());
// age.setText(list.get(position).getAge()+""); // 使用ListView回收机制
// if (convertView == null)
// convertView = LayoutInflater.from(context).inflate(R.layout.item,
// null);
// TextView username = (TextView)
// convertView.findViewById(R.id.username);
// TextView nickname = (TextView)
// convertView.findViewById(R.id.nickname);
// TextView age = (TextView) convertView.findViewById(R.id.age);
// username.setText(list.get(position).getUsername());
// nickname.setText(list.get(position).getNickname());
// age.setText(list.get(position).getAge()+""); // 终极版
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(context).inflate(R.layout.item,
null);
viewHolder.username = (TextView) convertView
.findViewById(R.id.username);
viewHolder.nickname = (TextView) convertView
.findViewById(R.id.nickname);
viewHolder.age = (TextView) convertView.findViewById(R.id.age);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.username.setText(list.get(position).getUsername());
viewHolder.nickname.setText(list.get(position).getNickname());
viewHolder.age.setText(list.get(position).getAge() + "");
return convertView;
}

  • 第五布:三种方式比较

    上面我们介绍了三种方式,孰优孰劣,还是要数据说话,我们在getView开始和结束的时候加上时间统计方法,看看三种方式到底花费了多少时间。真是不比不知道,一比吓一跳。







    不使用回收机制真的太可怕了!!!

  • 总结

    为了使我们的程序获得良好的性能,建议大家使用上文中第四步介绍的方式来使用BaseAdapter。

本项目完整代码下载


版权声明:本文为博主原创文章,未经博主允许不得转载。若有错误地方,还望批评指正,不胜感激。

BaseAdapter优化深入分析的更多相关文章

  1. Android学习总结(十二)———— BaseAdapter优化

    一.BaseAdapter的基本概念 对于Android程序员来说,BaseAdapter肯定不会陌生,灵活而优雅是BaseAdapter最大的特点.开发者可以通过构造BaseAdapter并搭载到L ...

  2. Android编码学习之Adapter

    1. Apter的作用 Adapter是将数据绑定到UI界面上的桥接类.Adapter负责创建显示每个项目的子View和提供对下层数据的访问.Adapter的作用就是将要在列表内显示的数据和列表本身结 ...

  3. 02-11Android学习进度报告十一

    今天我学习了BaseAdapter优化的知识,主要是View方面的优化. 首先是复用复用ConvertView 代码示例: @Override public View getView(int posi ...

  4. Android关于listView的BaseAdapter以及getView的三级优化

    1.4个重写方法的含义 自定义Adapter继承自BaseAdapter(通用适配器)   getCount(); getItem(); getItemId(); getViewTypaCount() ...

  5. 深入分析PHP优化及注意事项

    深入分析PHP优化及注意事项 1.尽量静态化: 如果一个方法能被静态,那就声明它为静态的,速度可提高1/4,甚至我测试的时候,这个提高了近三倍. 当然了,这个测试方法需要在十万级以上次执行,效果才明显 ...

  6. 关于BaseAdapter的使用及优化心得(一)

    对于Android程序员来说,BaseAdapter肯定不会陌生,灵活而优雅是BaseAdapter最大的特点.开发者可以通过构造BaseAdapter并搭载到ListView或者GridView这类 ...

  7. 【Android】以BaseAdapter做适配器的ListView及其性能优化

    适配器的Java类 package com.app.adapter; import org.json.JSONArray; import org.json.JSONObject; import and ...

  8. BaseAdapter以及对ListView的优化(转)

    背景 对于ListView.GridView.Gallery.Spinner等等,它是它们的适配器,直接继承自接口类Adapter的,使用BaseAdapter时需要重写很多方法,其中最重要的当属ge ...

  9. Android中的自定义Adapter(继承自BaseAdapter)——与系统Adapter的调用方法一致——含ViewHolder显示效率的优化(转)

    Android中很多地方使用的是适配器(Adapter)机制,那我们就要好好把这个Adapter利用起来,并且用出自己的特色,来符合我们自行设计的需要喽~~~ 下面先上一个例子,是使用ViewHold ...

随机推荐

  1. Gabor变换

    Gabor变换 Gabor变换属于加窗傅立叶变换,Gabor函数可以在频域不同尺度.不同方向上提取相关的特征.另外Gabor函数与人眼的生物作用相仿,所以经常用作纹理识别上,并取得了较好的效果.Gab ...

  2. [topcoder]IncreasingSubsequences

    http://community.topcoder.com/stat?c=problem_statement&pm=7753&rd=10672 http://community.top ...

  3. struts一点心得

    action中: 设置属性并增加get,set方法,给属性赋值后 (如: private String name; public String getName() { return name; } p ...

  4. 【HDOJ】3487 Play with Chain

    Splay入门题目,区间翻转,区间分割. /* */ #include <iostream> #include <string> #include <map> #i ...

  5. how to uninstall devkit

    http://www.uninstallapp.com/article/How-to-uninstall-Perl-Dev-Kit-PDK-8.0.1.289861.html PerfectUnins ...

  6. Unity3D-基本导航(NavMesh)功能实现

    1: 打开场景 2:打开Navgation窗口 菜单中: Window --> Navgation, 在Inspector旁边会出现导航界面 这个Objcet的面板是对应当前选择的物体的,旁边的 ...

  7. (转载)mysql decimal、numeric数据类型

    (转载)http://www.cnblogs.com/qiantuwuliang/archive/2010/11/03/1867802.html 可能做程序的人都知道,float类型是可以存浮点数(即 ...

  8. DevExpress中,添加Winform窗体到DockPanel z

    DevExpress中,添加Winform窗体到DockPanel // 在使用DevExpress过程中,原先已经创建好的导航窗体,如何添加到DockPanel中进行展示? FormX frmX = ...

  9. IIS服务器设置造成引用第三方权限不足问题

    使用IIS部署站点,报以下错误: Exception Details: System.Security.SecurityException: That assembly does not allow ...

  10. Delphi TcxTreeList 怎么设置分组

    Delphi 的TcxTreeList控件设置按种类分组,操作如下: 1. 在TcxTreeList控件中双击,打开 Bands 属性,在这里面建需要分的组,在Captions->Text 输入 ...