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

android中ListView的优化方案详解分析

2016-12-09 19:31 459 查看
Android中的ListView应该算是布局中几种最常用的组件之一了,使用也十分方便,我的上一篇博客讲了没有和优化的ListView,下面将介绍ListView几种比较常见的优化方法:

对于ListView的优化主要在自定义的Adapt中进行优化,其他的地方可优化的比较少,因此这几种不同的方案都是在对自定义的Adapt进行优化。

两个主要的布局文件和MainActivity.java

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"
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.ecjtu.optimizationlistview.MainActivity" >

<ListView android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/lv"></ListView>

</RelativeLayout>


mylayout.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="match_parent" >

<ImageView android:layout_height="match_parent"
android:layout_width="80dp"
android:id="@+id/image"
android:src="@drawable/ic_launcher"/>
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/title"
android:layout_toRightOf="@id/image"/>
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/content"
android:layout_below="@id/title"
android:layout_toRightOf="@id/image"/>
</RelativeLayout>

MainActivity.java

package com.ecjtu.optimizationlistview;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;

public class MainActivity extends Activity {
private ListView listView;
private List<Map<String, Object>> data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
data = new ArrayList<>();
listView = (ListView)findViewById(R.id.lv);
for (int i = 1; i < 101; i++) {
Map<String, Object> map = new HashMap<>();
map.put("image", R.drawable.ic_launcher);
map.put("title", "标题:"+i);
map.put("content", "内容为:"+i);
data.add(map);
}//初始化数据

listView.setAdapter(new MyAdapt(this,data));
}

}


一 方案一
这种优化也是最普通的优化,优化力度比较低,我们注意到每次我们在执行getView方法是都是重新生成了一个View对象,而每次执行getView方法都要生成View,这样就没有很好的利用好View,因此我们想到的做法就是对view进行复用。

我们可以注意到在getView方法中提供了一个View对象ConvertView,经过测试我们可以发现,其实程序开始执行时,在ListView显示的所有项中的时候ConertView都为null,当对屏幕进行滑动(开始翻页)的时候并且第一行开始消失的时候,ConvertView开始不为null了,下面的图片就是这种情景:



当第一行被挤出去的时候,ConvertView会自动保存第一行的View对象以供下面的行使用,这样就可以利用这个来对其进行优化。代码如下:

package com.ecjtu.optimizationlistview;

import java.util.List;
import java.util.Map;

import android.
4000
content.Context;
import android.media.Image;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class MyAdapt extends BaseAdapter {
private Context context;
private List<Map<String, Object>> data;
public MyAdapt(Context context,List<Map<String, Object>> data){
this.context = context;
this.data = data;
}

@Override
public int getCount() {
// TODO Auto-generated method stub
return data.size();
}

@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return data.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
Map<String, Object> map = data.get(position);

if (convertView==null) {
convertView = View.inflate(context, R.layout.mylayout, null);
}
ImageView imageView = (ImageView) convertView.findViewById(R.id.image);
TextView title = (TextView)convertView.findViewById(R.id.title);
TextView content = (TextView)convertView.findViewById(R.id.content);
imageView.setImageResource((Integer)map.get("image"));
title.setText((String)map.get("title"));
content.setText((String)map.get("content"));
return convertView;
}

}


二 方案二
对于上种优化方案,我们可以发现imageView、title、content还是要重复查找,想象一下要是如果组件多的话也是挺费事的,如果我们可以让view内的组件也随着view的复用而复用,那该是多美好的一件事啊。实际上谷歌官方也推荐了一种做法,就是把view中的组件构建成一个静态类的属性,这样就能对其进行重复利用。

静态类:

static class ViewHold{
ImageView imageView;
TextView title;
TextView content;
}

那么这个viewHolder类我们要如何使用才可以达到复用效果呢?基本思路就是在convertView为null的时候,我们不仅重新inflate出来一个view,并且还需要进行findviewbyId的查找工作,但是同时我们还需要获取一个ViewHolder类的对象,并将findviewById的结果赋值给ViewHolder中对应的成员变量。最后将holder对象与该view对象“绑”在一块。当convertView不为null时,我们直接使用converView,同时取出这个converView对应的holder对象,就获得了这个converView对象中的各个组件,它就是holder中的成员变量,这样在复用的时候,我们就不需要再去findViewById了,只需要在最开始的时候进行数次查找工作就可以了。这里的关键在于如何将view与holder对象进行绑定,那么就需要用到两个方法:setTag和getTag方法了:

整合MyAdapt后的代码为:
package com.ecjtu.optimizationlistview;

import java.util.List;
import java.util.Map;

import android.content.Context;
import android.media.Image;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class MyAdapt extends BaseAdapter {
private Context context;
private List<Map<String, Object>> data;
public MyAdapt(Context context,List<Map<String, Object>> data){
this.context = context;
this.data = data;
}

@Override
public int getCount() {
// TODO Auto-generated method stub
return data.size();
}

@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return data.get(position);
}

@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}

ViewHold viewHold;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
Map<String, Object> map = data.get(position);
if (convertView==null) {
convertView = View.inflate(context, R.layout.mylayout, null);
viewHold = new ViewHold();
viewHold.imageView = (ImageView) convertView.findViewById(R.id.image);
viewHold.title = (TextView) convertView.findViewById(R.id.title);
viewHold.content = (TextView) convertView.findViewById(R.id.content);
convertView.setTag(viewHold);//将viewHold加入到convertView中进行存储,以便后面使用
}else {
viewHold = (ViewHold) convertView.getTag();//直接从convertView取出使用
}
viewHold.imageView.setImageResource((Integer)map.get("image"));
viewHold.title.setText((String)map.get("title"));
viewHold.content.setText((String)map.get("content"));
/*if (convertView==null) {
convertView = View.inflate(context, R.layout.mylayout, null);
}
ImageView imageView = (ImageView) convertView.findViewById(R.id.image);
TextView title = (TextView)convertView.findViewById(R.id.title);
TextView content = (TextView)convertView.findViewById(R.id.content);
imageView.setImageResource((Integer)map.get("image"));
title.setText((String)map.get("title"));
content.setText((String)map.get("content"));*/
return convertView;
}
//静态类,属性为view中的组件
static class ViewHold{
ImageView imageView;
TextView title;
TextView content;
}
}


结果图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息