Android学习历程14-Android ListView优化
2016-02-23 19:02
615 查看
列表的显示需要三个元素:
ListVeiw: 用来展示列表的View。适配器 : 用来把数据映射到ListView上
数据: 具体的将被映射的字符串,图片,或者基本组件。
ListView的工作原理如下:
ListView 针对每个item,要求 adapter “返回一个视图” (getView),也就是说ListView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到ListView的长度,然后根据这个长度,调用getView()一行一行的绘制ListView的每一项。如果你的getCount()返回值是0的话,列表一行都不会显示,如果返回1,就只显示一行。返回几则显示几行。如果我们有几千几万甚至更多的item要显示怎么办?为每个Item创建一个新的View?不可能!!!实际上Android早已经缓存了这些视图,大家可以看下下面这个截图来理解下,这个图是解释ListView工作原理的最经典的图了大家可以收藏下,不懂的时候拿来看看,加深理解,其实Android中有个叫做Recycler的构件,顺带列举下与Recycler相关的已经由Google做过N多优化过的东东比如:AbsListView.RecyclerListener、ViewDebug.RecyclerTraceType等等,要了解的朋友自己查下,不难理解,下图是ListView加载数据的工作原理(原理图看不清楚的点击后看大图):下面简单说下上图的原理:
如果你有几千几万甚至更多的选项(item)时,其中只有可见的项目存在内存(内存内存哦,说的优化就是说在内存中的优化!!!)中,其他的在Recycler中
ListView先请求一个type1视图(getView)然后请求其他可见的项目。convertView在getView中是空(null)的
当item1滚出屏幕,并且一个新的项目从屏幕低端上来时,ListView再请求一个type1视图。convertView此时不是空值了,它的值是item1。你只需设定新的数据然后返回convertView,不必重新创建一个视图
ListView的优化:
(前两点都是利用ListView的自身优化机制优化【缓存优化】)1.利用ListView自身的缓存机制,他会缓存条目中的一个条目item,当listview第一屏显示完成之后,就会出现一个缓存条目,其实就是BaseAdapter里面的public View getView(int position, View convertView, ViewGroup parent)。
2.减少findViewById()的次数,findViewById是一个相对比较耗性能的操作,因为这个操作每次都需要到布局中去查找文件。把item里面的控件封装成一个javaBean,当item条目被加载的时候就去找到对应的控件。
3.利用时间去换取时间,比如开机优化,把一些重要的程序先启动了,启动完系统之后再启动其他程序。
4.利用空间去换取时间,把要获取的数据先加载到内存里面,再处理数据的时候,直接从内存中获取。
直接附上源代码
MainActivity中的代码
package com.example.androidlistview; import java.util.ArrayList; import java.util.HashMap; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { private ListView lv; //定义一个动态数组 ArrayList<HashMap<String, Object>> listItem; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv = (ListView) findViewById(R.id.lv); MyAdapter mAdapter = new MyAdapter(this);//得到一个MyAdapter对象 lv.setAdapter(mAdapter);//为ListView绑定Adapter /**为ListView添加点击事件*/ lv.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) { Toast.makeText(MainActivity.this, "你点击了ListView条目" + arg2, Toast.LENGTH_LONG).show(); } }); } /**添加一个得到数据的方法,方便使用*/ private ArrayList<HashMap<String, Object>> getDate(){ listItem = new ArrayList<HashMap<String,Object>>(); /**为动态数组添加数据*/ for(int i=0;i<30;i++) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("ItemTitle", "第"+i+"行"); map.put("ItemText", "这是第"+i+"行"); listItem.add(map); } return listItem; } /** 新建一个类继承BaseAdapter,实现视图与数据的绑定 */ private class MyAdapter extends BaseAdapter { private LayoutInflater mInflater;//得到一个LayoutInfalter对象用来导入布局 /**构造函数*/ public MyAdapter(Context context) { this.mInflater = LayoutInflater.from(context); } @Override public int getCount() { return getDate().size();//返回数组的长度 } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } /**书中详细解释该方法*/ @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder holder; //观察convertView随ListView滚动情况 Log.v("MyListViewBase", "getView " + position + " " + convertView); if (convertView == null) { convertView = mInflater.inflate(R.layout.listview_item,null); holder = new ViewHolder(); /**得到各个控件的对象*/ holder.title = (TextView) convertView.findViewById(R.id.ItemTitle); holder.text = (TextView) convertView.findViewById(R.id.ItemText); holder.bt = (Button) convertView.findViewById(R.id.ItemButton); convertView.setTag(holder);//绑定ViewHolder对象 } else{ holder = (ViewHolder)convertView.getTag();//取出ViewHolder对象 } /**设置TextView显示的内容,即我们存放在动态数组中的数据*/ holder.title.setText(getDate().get(position).get("ItemTitle").toString()); holder.text.setText(getDate().get(position).get("ItemText").toString()); /**为Button添加点击事件*/ holder.bt.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "你点击了按钮" + position, Toast.LENGTH_LONG).show(); } }); return convertView; } } /**存放控件*/ public final class ViewHolder{ public TextView title; public TextView text; public Button bt; } }
activity_main 布局文件的代码
<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"> <ListView android:id="@+id/lv" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </RelativeLayout>
listview_item中的布局代码
<?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="60dp" android:orientation="horizontal" > <LinearLayout android:layout_height="match_parent" android:layout_weight="7" android:layout_width="0dp" android:orientation="vertical"> <TextView android:id="@+id/ItemTitle" android:layout_weight="1" android:layout_height="0dp" android:layout_width="wrap_content" android:text="姓名"/> <TextView android:id="@+id/ItemText" android:layout_weight="1" android:layout_height="0dp" android:layout_width="wrap_content" android:text="年龄"/> </LinearLayout> <Button android:id="@+id/ItemButton" android:layout_weight="1" android:layout_height="match_parent" android:layout_width="0dp" android:text="Click" android:focusable="false"/> </LinearLayout>
运行界面如图所示:
相关文章推荐
- Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能
- android:viewpager实现图片循环滑动+索引点击事件
- Android远程服务与本地服务的特点以及功能差异
- android的adb命令以及测试
- 获得activity的类名
- Socket通信,Android,java
- Android Studio NDK使用
- Android查看SHA1值
- Android 三大图片缓存原理、特性对比
- Android Service与IntentService区别
- 将Eclipse代码导入到AndroidStudio的两种方式
- 第11章 Android的线程和线程池
- Android Audio system Overview
- Android上实现仿IOS弹性ScrollView
- android listview优化
- Android建立模拟器进行调试
- android studio插件推荐
- android studio下的NDK开发详解(一)
- armeabi armeabi-v7a android
- Android应用程序 --- WakeLock 保持后台唤醒状态