展会信息港展会大全

ListView和性能 android开发教程
来源:互联网   发布日期:2015-11-26 17:07:37   浏览:2338次  

导读:一谈起ListView,我想大家都不陌生。而且最近该控件特别红,像QQ,人人和新浪客户端里都有它的影子。其实实现ListView非常的简单。我想大家都用过各种各样的控件,比如说一个最简单...

一谈起ListView,我想大家都不陌生。而且最近该控件特别红,像QQ,人人和新浪客户端里都有它的影子。

其实实现ListView非常的简单。

我想大家都用过各种各样的控件,比如说一个最简单的TextView,我们都是在布局文件里加入TextView标签,然后在Activity里通过findViewById(int id)方法得到该对象的引用,最后调用TextView类的setText(CharSequence s)方法设置该控件的值。

同样,对于ListView,我们先在布局文件里这样添加标签:

[html]

<?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" >

<ListView

android:id="@+id/mylist"

android:layout_width="match_parent"

android:layout_height="wrap_content" >

</ListView>

</LinearLayout>

有了布局文件,然后我们在Activity里通过findViewById(int id)方法得到ListView对象的引用

[java]

ListView listView = (ListView) findViewById(R.id.mylist);

有了控件还不行,我们可以把ListView看作是一个可以伸缩的容器,我们需要往里添加内容。作为数据传输的桥梁,Adapter封装了所需的数据,通过调用ListView的方法setAdapter(Adapter a)将数据绑定到ListView中,这样屏幕上就有数据显示了。

Adapter是一个接口,定义了许多规范。Android提供了实现该接口的一些方便的类,如ArrayAdapter,CursorAdapter。下面以ArrayAdapter类为例讲解如何创建一个Adapter。

[java]

String[] values = new String[] { "Android", "iPhone", "WindowsMobile",

"Blackberry", "WebOS", "Ubuntu", "Windows7", "Max OS X",

"Linux", "OS/2" };

// First paramenter - Context

// Second parameter - Layout for the row

// Third parameter - ID of the TextView to which the data is written

// Forth - the Array of data

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,

android.R.layout.simple_list_item_1, android.R.id.text1, values);

是不是很简单?在上面的那个构造方法中,一共有四个参数,第一个参数很简单,就是一个上下文对象Context,第二个参数是描述每一行的布局,这里使用的是Android自带的一个简单布局,第三个参数是该View的id,最后一个是加入的数组。

上面的ArrayAdapter只能在每一行显示一些文本信息,如果想丰富一下,比如增加图片等,就需要继承该类,实现自己的自定义类。

[java

public class MySimpleArrayAdapter extends ArrayAdapter<String> {

private final Context context;

private final String[] values;

public MySimpleArrayAdapter(Context context, String[] values) {

super(context, R.layout.rowlayout, values);

this.context = context;

this.values = values;

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

LayoutInflater inflater = (LayoutInflater) context

.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

View rowView = inflater.inflate(R.layout.rowlayout, parent, false);

TextView textView = (TextView) rowView.findViewById(R.id.label);

ImageView imageView = (ImageView) rowView.findViewById(R.id.icon);

textView.setText(values[position]);

String s = values[position];

imageView.setImageResource(R.drawable.ok);

return rowView;

}

}

继承该类最关键的就是复写getView()方法,因为ListView是通过该方法得到视图然后显示在屏幕上的。在本方法中,我们自定义了一个XML布局文件,里面有TextView标签和ImageView标签,分别用来显示文字和图片信息,这里是先得到系统服务LayoutInflater,调用该方法的inflate得到该布局的View,最后通过findViewById()方法获取TextView和ImageView的对象引用,再给它们赋值返回就结束了。

但是本章的讨论不是讲解如何实现ListView,但是考虑到有些没有接触过ListView的同志,就大概写了一点demo,同时以此例子为引子,指出该方法存在的一些性能问题。

由于通过调用LayoutInflater的inflate方法获得的View,其实会产生新的对象,创建对象是很耗时和资源的(内存),另外调用getViewById()方法也会相对耗时和耗资源,虽然其强度不如前者。

所以Android决定,如果代表每一行的View不可见(向下滑动,上面的View被遮住了,即为不可见),那么它将允许getView方法通过convertView复用该View,达到提升性能的目的。

我们先来看下ArrayAdapter是如何进行优化的。

[java]

public View getView(int position, View convertView, ViewGroup parent) {

return createViewFromResource(position, convertView, parent, mResource);

}

private View createViewFromResource(int position, View convertView, ViewGroup parent,

int resource) {

View view;

TextView text;

if (convertView == null) {

view = mInflater.inflate(resource, parent, false);

} else {

view = convertView;

}

try {

if (mFieldId == 0) {

//If no custom field is assigned, assume the whole resource is a TextView

text = (TextView) view;

} else {

//Otherwise, find the TextView field within the layout

text = (TextView) view.findViewById(mFieldId);

}

} catch (ClassCastException e) {

Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");

throw new IllegalStateException(

"ArrayAdapter requires the resource ID to be a TextView", e);

}

T item = getItem(position);

if (item instanceof CharSequence) {

text.setText((CharSequence)item);

} else {

text.setText(item.toString());

}

return view;

}

该方法首先判断传给该方法的convertView是否为null,如果为null,那么就调用耗时的inflate方法创建View对象,如果不为空(该convertView是以前inflate过的,只不过被遮住了),就复用该对象,达到了部分优化。

上面之所以说是部分优化,是因为只考虑了优化inflate带来的负载,而忽略了getViewById()方法引起的性能问题。解决办法是在自定义Adapter类里引进静态内部类ViewHolder,如其名字,该类里存放我们需要显示每一行的所有控件,比如TextView,ImageView等。当convertView为空时,我们创建布局文件的View,然后分别得到布局里的各种控件,再把它们存放在ViewHolder类里,最后再调用convertView的 setTag(Object o)方法把该类绑定到该类里。

[java]

public class MyPerformanceArrayAdapter extends ArrayAdapter<String> {

private final Activity context;

private final String[] names;

static class ViewHolder {

public TextView text;

public ImageView image;

}

public MyPerformanceArrayAdapter(Activity context, String[] names) {

super(context, R.layout.rowlayout, names);

this.context = context;

this.names = names;

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

View rowView = convertView;www.2cto.com

if (rowView == null) {

LayoutInflater inflater = context.getLayoutInflater();

rowView = inflater.inflate(R.layout.rowlayout, null);

ViewHolder viewHolder = new ViewHolder();

viewHolder.text = (TextView) rowView.findViewById(R.id.TextView01);

viewHolder.image = (ImageView) rowView

.findViewById(R.id.ImageView01);

rowView.setTag(viewHolder);

}

ViewHolder holder = (ViewHolder) rowView.getTag();

String s = names[position];

holder.text.setText(s);

if (s.startsWith("Windows7") || s.startsWith("iPhone")

|| s.startsWith("Solaris")) {

holder.image.setImageResource(R.drawable.no);

} else {

holder.image.setImageResource(R.drawable.ok);

}

return rowView;

}

}

根据统计信息,这样的优化设计,比最初的方法效率上要快15%以上。

赞助本站

人工智能实验室

相关热词: android开发 教程

AiLab云推荐
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港