您的位置:首页 > 移动开发 > Android开发

android开发笔记之ListView的优化+分类显示

2016-05-21 21:26 786 查看
今天来讲讲在APP中90%要使用到的一个组件—–> ListView

听到这,大家觉得应该是再熟悉不过了吧,当然或许很多人已经知道 ListView 的优化。我在这里就再详细的讲一遍。顺便让ListView分类显示。

先来看看效果:



可以看到数据有100个(0-99),奇数和偶数分类显示,并给每类数据加了一个头

步骤:

①在布局文件中添加ListView组件

<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.listview.MainActivity" >
<ListView
android:id="@+id/listView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
</ListView>
</RelativeLayout>


②在主activity中找到该listView,并为它设置适配器

private ListView listView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
//初始化adapter
MyAdapter adapter = new MyAdapter();
//为listView设置适配器
listView.setAdapter(adapter);
}


③为ListView设置数据,这里就使用模拟数据(0-99),并把数据分成两类(奇数和偶数)

jiDatas = new ArrayList<String>();
ouDatas = new ArrayList<String>();
//将data进行奇数和偶数分类(模拟数据)
for (int i = 0; i < 100; i++) {
if (i%2 == 0) {
ouDatas.add(i+""); //偶数
}else {
jiDatas.add(i+""); //奇数
}
}


接下来重要的来了,定义适配器继承BaseAdapter,并实现四个方法

public int getCount() //返回listView有多少个条目

public Object getItem(int position) //返回位置为position的条目

public long getItemId(int position) //返回位置为position的条目的Id

public View getView(int position, View convertView, ViewGroup parent) //返回每个条目的视图

中间两个方法目前还用不到。主要方法是getView()方法。

前面三个方法比较简单我就直接写:

class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
//注意为什么要加2呢,因为把数据分成了两类,加了两个头,就增加了两个条目
return 1+jiDatas.size()+1+ouDatas.size();
}
@Override
public Object getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}


现在看看最重要的一个方法getView,也就是在这里面对ListView的优化和分类显示。

首先不优化的时候的写法是:

public View getView(int position, View convertView, ViewGroup parent) {
View view = view = View.inflate(MainActivity.this, R.layout.myitem, null);
TextView tv = (TextView) view.findViewById(R.id.tv);
tv.setText(data.get(position));
return view;
}


我们知道getView的调用次数,是有多少个条目就调用多少次吧,那么上面这么写的加载布局和findViewById就会调用100次吧,而每个条目的布局都一样,为什么要重复加载呢,所以要想办法减少加载布局的次数,怎么做呢。

我们可以看到getView方法有三个参数,第二个参数convertView还没有使用到,对,有人应该知道就是缓存。

convertView工作原理:



注:

这里屏幕只显示8个条目,你的可能不是,因为每个手机的屏幕大小不一样嘛,不过原理都是一样的。

看到这里我们知道了convertView,所以接下来使用convertView来减少加载布局的次数:

public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = View.inflate(MainActivity.this, R.layout.myitem, null);
}
TextView tv = (TextView) convertView.findViewById(R.id.tv);
tv.setText(data.get(position));
return convertView ;
}


这样加载视图就只会调用它第一屏的条目的数量。比如:第一屏显示8个条目,加载视图会调用8次,以后滑动就不会调用了。

到这里看起来是可以了,但是我们可以注意到findViewById也到调用了100次呀,也挺多的,能不能减少呢,答案是肯定的。

解决办法:

定义一个ViewHolder,将convertView的tag设置为ViewHolder,不为空时重新使用

ViewHolder只是将需要缓存的那些view封装好,convertView的setTag才是将这些缓存起来供下次调用

当你的listview里布局多样化的时候 viewholder的作用就有比较明显的体现了。 当然了,单一模式的布局一样有性能优化的作用 只是不直观。

VH就是个静态类 与缓存无关的

public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
//缓存:convertView调用的次数为第一屏item的数目
//findViewById调用的次数为第一屏item的数目
//滑动的时候convertView的布局不一样,所以需要加个判断
//如果是ViewGroup(即TextView的父容器)的实例就从Tag中取
if (convertView != null && convertView instanceof ViewGroup) {
viewHolder = (ViewHolder) convertView.getTag();
}else {
convertView = View.inflate(MainActivity.this, R.layout.myitem, null);
viewHolder = new ViewHolder();
viewHolder.tv = (TextView) convertView.findViewById(R.id.tv);
convertView.setTag(viewHolder);
}
viewHolder.tv.setText(data);
return convertView;
}
static class ViewHolder {
public TextView tv;
}


为什么要这样写呢

if (convertView != null && convertView instanceof ViewGroup) {}

因为头的布局和item的布局不一样,不能够全部复用,所以要判断下。

这样就又减少了findViewById的次数了,又再一次优化了。

优化完成了,接下来实现分类显示,首先分析:

数据0-99,分成奇数和偶数,所以各有50个,头的位置分别加在 position = 0 的时候和 position = 51 的时候。

所以:

public View getView(int position, View convertView, ViewGroup parent) {
String data;
if (position == 0) {
//position为0时加载头,结束本次方法调用
TextView textView = new TextView(getApplicationContext());
textView.setText("奇数" + jiDatas.size());
return textView;
}else if (position <= jiDatas.size()) {
//position为[1-50]时加载奇数数据
data = jiDatas.get(position - 1);
}else if (position == jiDatas.size() + 1) {
//position为51时加载头,结束本次方法调用(因为奇数为50条)
TextView textView = new TextView(getApplicationContext());
textView.setText("偶数" + ouDatas.size());
return textView;
}else {
//position为[52-101]时加载偶数数据
data = ouDatas.get(position-jiDatas.size()-2);
}
return convertView ;
}


到这里就已经实现了上面的效果。

核心代码:

activity_main.xml

<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.listview.MainActivity" >
<ListView
android:id="@+id/listView"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

</ListView>
</RelativeLayout>


MainActivity.java

public class MainActivity extends Activity {

private ListView listView;
//总的数据的集合
private List<String> data;
//存放奇数的集合
private List<String> jiDatas;
//存放偶数的集合
private List<String> ouDatas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
data = new ArrayList<String>();
jiDatas = new ArrayList<String>();
ouDatas = new ArrayList<String>();
//将data进行奇数和偶数分类(模拟数据)
for (int i = 0; i < 100; i++) {
if (i%2 == 0) {
ouDatas.add(i+""); //偶数
}else {
jiDatas.add(i+""); //奇数
}
}
//初始化adapter
MyAdapter adapter = new MyAdapter();
//为listView设置适配器
listView.setAdapter(adapter);

}
class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return 1+jiDatas.size()+1+ouDatas.size();
}
@Override
public Object getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//          //普通式
//          if (convertView == null) {
//              convertView = View.inflate(MainActivity.this, R.layout.myitem, null);
//          }
//          TextView tv = (TextView) convertView.findViewById(R.id.tv);
//          tv.setText(data.get(position));

String data;
if (position == 0) {
//position为0时加载头,结束本次方法调用
TextView textView = new TextView(getApplicationContext());
textView.setText("奇数" + jiDatas.size());
return textView;
}else if (position <= jiDatas.size()) {
//position为[1-50]时加载奇数数据
data = jiDatas.get(position - 1);
}else if (position == jiDatas.size() + 1) {
//position为51时加载头,结束本次方法调用(因为奇数为50条)
TextView textView = new TextView(getApplicationContext());
textView.setText("偶数" + ouDatas.size());
return textView;
}else {
//position为[52-101]时加载偶数数据
data = ouDatas.get(position-jiDatas.size()-2);
}

//文艺式
ViewHolder viewHolder = null;
//缓存:convertView调用的次数为第一屏item的数目
//findViewById调用的次数为第一屏item的数目
//滑动的时候convertView的布局不一样,所以需要加个判断
//如果是ViewGroup(即TextView的父容器)的实例就从Tag中取
if (convertView != null && convertView instanceof ViewGroup) {
viewHolder = (ViewHolder) convertView.getTag();
}else {
convertView = View.inflate(MainActivity.this, R.layout.myitem, null);
viewHolder = new ViewHolder();
viewHolder.tv = (TextView) convertView.findViewById(R.id.tv);
convertView.setTag(viewHolder);
}
viewHolder.tv.setText(data);

//          //逗比式
//          View view = view = View.inflate(MainActivity.this, R.layout.myitem, null);
//          TextView tv = (TextView) view.findViewById(R.id.tv);
//          tv.setText(data.get(position));
return convertView;
}
}
static class ViewHolder {
public TextView tv;
}
}


myitem.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" >

<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="100dp"
android:textSize="20sp"
android:gravity="center"/>

</LinearLayout>


源码下载地址:http://download.csdn.net
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: