Android开发之ListView优化方案

我们使用ViewHolder时,把每一个item的子View控件对象都放在ViewHolder中,当第一次创建convertView对象时,便把这些item的子View控件对象findViewById实例化出来并保存到ViewHolder的对象中。然后用convertView的setTag将viewHolder对象设置到Tag中, 当以后加载ListView的item时便可以直接从Tag中取出复用ViewHolder对象中的,不需要再findViewById找item的子控件对象了。这样便大大提高了性能。

但是,某些情况下,这种优化技术便出现了一种问题,举个例子,当我们由于项目需要,需要在ListView中用到CheckBox时,那么,就会出现这样的情况:

假设一个ListView有10个Item,当我选择第一个Item的CheckBox之后,往下滑动到原先不可见的位置时就会发现,还有其他的CheckBox也被选中了,这样就造成了很不好的用户体验。

先上出现了这种问题的代码:

布局文件:

activity_listview.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
<ListView
    android:id="@+id/listview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"></ListView>
</LinearLayout>
item_list.xml   一个CheckBox和一个TextView,设为100dp高的原因是,必须有未显示的Item,ListView才会去复用View,如果一个屏幕显示了全部的Item,那么就不回复用了。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="100dp">
    <CheckBox
        android:layout_centerVertical="true"
        android:layout_marginLeft="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/textView"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>
</LinearLayout>
MyAdapter.java

package cn.zmit.myapplication;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

/**
 * Created by Administrator on 2016/3/23.
 */
public class MyAdapter extends BaseAdapter {
    private List<String> list;
    private Context context;

    public MyAdapter(List<String> lists, Context contexts) {

        list = lists;
        context = contexts;
    }

    @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(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = View.inflate(context, R.layout.item_list, null);
            holder.textView = (TextView) convertView.findViewById(R.id.textView);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.textView.setText(list.get(position));

        return convertView;
    }

    private class ViewHolder {
        TextView textView;
    }
}
ListVeiwDemo.java

package cn.zmit.myapplication;

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

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2016/3/18.
 */
public class ListViewDemo extends Activity {
    private ListView listView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_listview);
        listView= (ListView) findViewById(R.id.listview);
        List<String> list=new ArrayList<>();
        for(int i=0;i<10;i++){
            list.add(i+"");
        }
        MyAdapter adapter=new MyAdapter(list,this);
        listView.setAdapter(adapter);
    }

}
 

非常正常的一个ListView实现过程,贴代码的原因是担心有初学者不懂我在说什么。大家可以把代码拷贝一下或者自己编写看一下效果。

 

接下来说一下怎么解决!!!!
首先,定义一个Map,

Map<Integer,View>map=new HashMap<>();
当convertView为null时,在convertView和子控件加载完成后,将convertView加入map:

map.put(position,convertView);
我们想一想,这时候,在前面判断的时候,还应该是

if (convertView == null)
这样吗?当然不是,换成这样:

if (map.get(position)==null)
也就是说,只要你这个Item没被加载过,就给我重新加载!

然后在下面的else里这样写:

else {
    convertView=map.get(position);
    holder = (ViewHolder) convertView.getTag();
}
假设map里有这个View,就拿出来用。

全部解决完问题的Adapter的getView部分代码为:
Map<Integer,View>map=new HashMap<>();
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (map.get(position)==null) {
        holder = new ViewHolder();
        convertView = View.inflate(context, R.layout.item_list, null);
        holder.textView = (TextView) convertView.findViewById(R.id.textView);
        map.put(position,convertView);
        convertView.setTag(holder);
    } else {
        convertView=map.get(position);
        holder = (ViewHolder) convertView.getTag();
    }
    holder.textView.setText(list.get(position));

    return convertView;
}

时间: 2024-11-05 20:46:19

Android开发之ListView优化方案的相关文章

Android开发之ListView实现Item局部刷新_Android

对于android中的ListView刷新机制,大多数的程序员都是很熟悉的,修改或者添加adapter中的数据源之后,然后调用notifyDataSetChanged()刷新ListView.在这种模式下,我们会在getView中,根据不同的数据源,让控件显示不同的内容.这种模式是最常见的刷新模式,当我们来回滑动ListView的时候,调用adapter的getView方法,然后listview对adapter返回的View进行绘制.这种模式下,View的显示内容或状态都记录在adapter里面

Android开发之ListView列表刷新和加载更多实现方法_Android

本文实例讲述了Android开发之ListView列表刷新和加载更多实现方法.分享给大家供大家参考.具体如下: 上下拉实现刷新和加载更多的ListView,如下: package com.sin.android.ui; import android.content.Context; import android.util.AttributeSet; import android.view.Gravity; import android.view.MotionEvent; import andro

Android开发之ListView的head消失页面导航栏的渐变出现和隐藏_Android

1.Fragment页面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开发之listView组件用法实例简析

本文实例讲述了android开发之listView组件用法.分享给大家供大家参考,具体如下: 关于Android ListView组件中android:drawSelectorOnTop含义 android:drawSelectorOnTop="true"  点击某一条记录,颜色会显示在最上面,记录上的文字被遮住,所以点击文字不放,文字就看不到. android:drawSelectorOnTop="false" 点击某条记录不放,颜色会在记录的后面,成为背景色,但

Android开发之ListView实现Item局部刷新

对于android中的ListView刷新机制,大多数的程序员都是很熟悉的,修改或者添加adapter中的数据源之后,然后调用notifyDataSetChanged()刷新ListView.在这种模式下,我们会在getView中,根据不同的数据源,让控件显示不同的内容.这种模式是最常见的刷新模式,当我们来回滑动ListView的时候,调用adapter的getView方法,然后listview对adapter返回的View进行绘制.这种模式下,View的显示内容或状态都记录在adapter里面

Android开发之ListView列表刷新和加载更多实现方法

本文实例讲述了Android开发之ListView列表刷新和加载更多实现方法.分享给大家供大家参考.具体如下: 上下拉实现刷新和加载更多的ListView,如下: package com.sin.android.ui; import android.content.Context; import android.util.AttributeSet; import android.view.Gravity; import android.view.MotionEvent; import andro

Android开发之ListView的head消失页面导航栏的渐变出现和隐藏

1.Fragment页面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开发之ListView、GridView 详解及示例代码_Android

    ListView与GridView是Android开发中的常用控件,它们和Adapter配合使用能够实现很多界面效果.下面分别以实例说明ListView.GridView的用法.        1.ListView的Android开发实例        ListView 是android开发中最常用的控件之一,一般构成列表包括三个元素,ListView:用来展示列表的视图.Adapter:数据与视图连接的桥梁.Data:具体的数据包括字符串 .图片或者控件.        适配器一般有以

Android开发之ListView,加入CheckBox(复选框),实现选择列表

http://blog.csdn.net/ahutzh/article/details/6911095 Android ListView没行加入CheckBox,实现选择列表,既可点击复选框进行选中,也可以点击list一行进行选中,效果图如下: 下面贴下主要代码的实现: 对于列表中复选框,我们需要在复选框的状态发生变化时,保存复选框的状态,不然在拖动列表过程中,会丢失复选框的状态. 在这里我们采用下面方式保存: [java] view plaincopy public class Person