文档章节

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

Mr_Nice
 Mr_Nice
发布于 2016/05/22 20:01
字数 1850
阅读 10
收藏 0
点赞 2
评论 0

今天来讲讲在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

© 著作权归作者所有

共有 人打赏支持
Mr_Nice
粉丝 0
博文 47
码字总数 39947
作品 0
广州
Android性能优化:这是一份详细的布局优化 指南(含、、)

前言 在 开发中,性能优化策略十分重要 本文主要讲解性能优化中的布局优化,希望你们会喜欢。 目录 /** 实例说明:在上述例子,在布局B中 通过标签引用布局C 此时:布局层级为 = RelativeLa...

Carson_Ho ⋅ 05/14 ⋅ 0

Android分页加载刷新AsyncListUtil中DataCallback的refreshData()

Android分页加载刷新AsyncListUtil中DataCallback的refreshData() Android分页加载刷新AsyncListUtil中DataCallback的refreshData()函数,返回值控制分页总数据量。如果返回一个既定的整型数...

zhangphil ⋅ 05/29 ⋅ 0

Android性能优化:手把手教你如何让App更快、更稳、更省(含内存、布局优化等)

前言 在 开发中,性能优化策略十分重要 因为其决定了应用程序的开发质量:可用性、流畅性、稳定性等,是提高用户留存率的关键 本文全面讲解性能优化中的所有知识,献上一份 性能优化的详细攻...

Carson_Ho ⋅ 05/30 ⋅ 0

Android 性能优化:手把手教你优化Bitmap图片资源的使用

前言 在 开发中,性能优化策略十分重要 本文主要讲解性能优化中的Bitmap 使用优化,希望你们会喜欢 目录 1. 优化原因 即 为什么要优化图片资源,具体如下图:

Carson_Ho ⋅ 04/24 ⋅ 0

Android性能优化:那些不可忽略的绘制优化

前言 在 开发中,性能优化策略十分重要 本文主要讲解性能优化中的绘制优化,希望你们会喜欢。 目录 // 方式2:在 BaseActivity 的 onCreate() 方法中使用下面的代码移除 优化方案2:移除 控件...

Carson_Ho ⋅ 05/21 ⋅ 0

Android RxJava: 这是一份全面的 操作符 使用汇总 (含详细实例讲解)

前言 ,由于其基于事件流的链式调用、逻辑简洁 & 使用简单的特点,深受各大 开发者的欢迎。 如果还不了解RxJava,请看文章:Android:这是一篇 清晰 & 易懂的Rxjava 入门教程 如此受欢迎的原...

Carson_Ho ⋅ 05/31 ⋅ 0

Android动画:献上一份详细 & 全面的动画知识学习攻略

前言 动画的使用 是 开发中常用的知识 可是动画的种类繁多、使用复杂,每当需要 采用自定义动画 实现 复杂的动画效果时,很多开发者就显得束手无策 本文将献上一份动画的全面介绍攻略,包括动...

Carson_Ho ⋅ 06/06 ⋅ 0

Android开发权威指南(第2版)新书发布

《Android开发权威指南(第二版)》是畅销书《Android开发权威指南》的升级版,内容更新超过80%,是一本全面介绍Android应用开发的专著,拥有45章精彩内容供读者学习。  《Android开发权威指...

androidguy ⋅ 2013/09/05 ⋅ 0

Google让Chromebook用户在Chrome OS中管理所有Android文件

Google Chromium开发者FrançoisBeaufort透露,Chrome操作系统团队正计划在Files应用中让Chromebook设备管理所有的Android文件。被称为“Android文件”的新功能已在Chrome OS Dev频道中实施,...

稿源:cnBeta.COM ⋅ 06/04 ⋅ 0

Android中ListView分类

引言 在Android开发过程中往往有这样的需求,将ListView中的内容按年,月,日进行分类显示,要实现这样的效果我们可能有很多种方法, 如:多ListView拼合,自定义ListView组件等,下面介绍一...

postdep ⋅ 2013/01/30 ⋅ 1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

SAS笔记-宏2

宏是一种文本,一般来说其编译是在程序执行之前。 宏变量的创建 %let语句 %let macro_variables = text; %let是常见的宏变量建立方式,其编译就在执行前。如下例中,想要宏变量test等于数据集...

tonorth123 ⋅ 8分钟前 ⋅ 0

如何使用serverchan微信推送告警

之前实现推送告警信息到微信的方法有如下几种: 1、通过企业公众号实现----收费: 2、通过QQ邮箱,在微信平台上开启收到邮件进行提醒; 3、第三方告警平台API,一般也是收费的; 不过最近看文...

问题终结者 ⋅ 35分钟前 ⋅ 0

TCP的RPC

RPC就是远程方法调用(Remote Process Call ),包含了客户端和服务端,涉及了对象的序列化传输。 1.服务端启动,注册远程调用的类2.客户端发送请求信息包含类、方法、参数的一些信息、序列化传...

Cobbage ⋅ 55分钟前 ⋅ 0

IOS-UI UI初步代码布局添加事件

ISO开发界面,UI是必须学习的一部分,其实很早之前想学来了,一直没有沉下心来学习。看到IOS的代码风格和布局就别扭的不行,跟java代码和android布局比较显得不是那么方便,所以一直到现在。...

京一 ⋅ 今天 ⋅ 0

浅谈OpenDaylight的二次开发

OpenDaylight作为一款开源SDN网络控制器,依托于强大的社区支持以及功能特性,成为了目前主流的SDN网络控制器开发平台。在比较稳定的OpenDaylight Helium版本中,已经为开发者提供了大量的网...

wangxuwei ⋅ 今天 ⋅ 0

API 开发中可选择传递 token 接口遇到的一个坑

在做 API 开发时,不可避免会涉及到登录验证,我使用的是jwt-auth 在登录中会经常遇到一个token过期的问题,在config/jwt.php默认设置中,这个过期时间是一个小时,不过为了安全也可以设置更...

等月人 ⋅ 今天 ⋅ 0

Java NIO之文件处理

程序要操作本地操作系统的一个文件,可以分为以下三个部分: 对文件位置的操作 对文件的操作 对文件内容的操作 其中,对文件内容的操作在 Java NIO之Channel 中已经有了介绍,通过FileChann...

士别三日 ⋅ 今天 ⋅ 0

Maven的pom.xml配置文件详解

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.......

小海bug ⋅ 今天 ⋅ 0

解决httpclient超时设置不生效的问题

最近公司有项目需要通过http调用第三方服务,且第三方服务偶有超时,故需要设置一定的超时时间防止不响应的情况出现。 初始设置如下: [java] view plain copy //超时设置 RequestConfig re...

Mr_Tea伯奕 ⋅ 今天 ⋅ 0

过滤器Filter和拦截器HandlerInterceptor

过滤器 依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要...

hutaishi ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部