随着ListView的不断深入使用,对于其的优化是必不可免的一个过程,现把其常见的优化步骤分享下,一些粗浅见识。。。

优化分四步走:

  第一,复用convertView对象,如果之前有条目对象,就复用,否则就去创建

  第二,为了减少findViewById次数,将findViewById已经找到的控件,做一个存储,存储到ViewHolder中,viewHolder存储到复用的convertView中

  第三,将ViewHolder定义成静态,字节码加载一次

  第四,通过分页算法,进一步优化用户体验(每一次加载20条数据,下一次加载的数据要添加到上一次数据后面)

详细步骤截图如下:

package cn.itae.listview_optimize;

import java.util.List;

import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Contacts.Intents.Insert;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;
import cn.itae.listview_optimize.db.dao.BlackNumberDao;
import cn.itae.listview_optimize.db.domain.BlackNumberInfo; public class MainActivity extends Activity { private ListView lv_blackNumber;
private Button bt_add;
private BlackNumberDao mDao;
private List<BlackNumberInfo> mBlackNumberList;
private int mTotalCount;
private MyAdapter mAdapter;
protected boolean isload = false;
private int mode = 1;
private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) {
// 给listView添加数据
if (mAdapter == null) {
mAdapter = new MyAdapter();
lv_blackNumber.setAdapter(mAdapter);
} else {
// /加载更多的时候,因为已经有数据适配,只需要做刷新即可
mAdapter.notifyDataSetChanged();
// 设置判断是否加载下一次数据的标识
// false允许开启下一次的加载过程
isload = false;
}
};
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); initUI(); initData();
} class MyAdapter extends BaseAdapter { public int getCount() { return mBlackNumberList.size();
} public BlackNumberInfo getItem(int position) { return mBlackNumberList.get(position);
} public long getItemId(int position) { return position;
} public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
// 1 、复用convertView
if (convertView == null) {
holder = new ViewHolder();
convertView = View.inflate(getApplicationContext(),
R.layout.list_item_view, null); // 2、通过ViewHolder类,减少findViewById的次数
// 获取条目上的控件
holder.tv_phone = (TextView) convertView
.findViewById(R.id.tv_phone);
holder.tv_mode = (TextView) convertView
.findViewById(R.id.tv_mode);
holder.iv_delete = (ImageView) convertView
.findViewById(R.id.iv_delete);
// 给convertView设置一个tag,tag就是要存储的holder对象
convertView.setTag(holder);
} else {
// 将convertView中的holder对象取出来,给复用的条目去做控件中的赋值操作
holder = (ViewHolder) convertView.getTag();
} // 给控件赋值
// 从集合中获取数据 给控件赋值
final BlackNumberInfo blackNumberInfo = mBlackNumberList
.get(position); holder.tv_phone.setText(blackNumberInfo.getPhone()); // 给图片按钮设置删除点击事件
holder.iv_delete.setOnClickListener(new OnClickListener() { public void onClick(View v) {
// 1从数据库中删除一条数据
mDao.delete(blackNumberInfo.getPhone());
// 2在集合中删除一条数据
mBlackNumberList.remove(blackNumberInfo); // 3.告知适配器刷新
mAdapter.notifyDataSetChanged();
}
}); // 显示模式
switch (blackNumberInfo.getMode()) {
case 1:
// 短信
holder.tv_mode.setText("拦截短信");
break;
case 2:
// 电话
holder.tv_mode.setText("拦截电话");
break;
case 3:
// 所有
holder.tv_mode.setText("拦截所有");
break;
} return convertView;
}
} // 4,分页算法(每一次加载20条数据,下一次加载的数据要添加到上一次数据后面),数据库,网络请求
// 3、将ViewHolder定义成静态,字节码文件只加载一次
static class ViewHolder {
TextView tv_phone;
TextView tv_mode;
ImageView iv_delete;
} /**
* 初始化数据,将之前加入黑名单的号码从数据库中获取出来
*/
private void initData() {
// 查询数据库中数据是耗时操作,需要放到子线程中去执行
new Thread() { public void run() {
mBlackNumberList = mDao.find(0);
mTotalCount = mDao.findTotalCount(); // 通过消息处理机制告知主线程可以使用获得的数据了
mHandler.sendEmptyMessage(0);
};
}.start();
} private void initUI() { mDao = BlackNumberDao.getInstance(this); lv_blackNumber = (ListView) findViewById(R.id.lv_blackNumber);
bt_add = (Button) findViewById(R.id.bt_add); bt_add.setOnClickListener(new OnClickListener() { public void onClick(View v) {
// 弹出对话框
showDialog();
}
}); lv_blackNumber.setOnScrollListener(new OnScrollListener() { public void onScrollStateChanged(AbsListView view, int scrollState) {
// 滚动状态发生改变方法
// OnScrollListener.SCROLL_STATE_FLING;正在飞速的滚动
// OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;用户触摸滚动
// OnScrollListener.SCROLL_STATE_IDLE;滚动状态有滚动--->空闲
// 如果由滚动变成空闲,并且滚动到最后一个条目
// (最后一个可见条目的索引>=集合大小-1)则需要加载更多数据 if (mBlackNumberList != null) {
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE && lv_blackNumber.getLastVisiblePosition() >= mBlackNumberList.size() - 1 && !isload) { if (mBlackNumberList.size() < mTotalCount) {
//加载下一页数据
new Thread(){
public void run() {
//下一页查询到的数据
List<BlackNumberInfo> moreData = mDao.find(mBlackNumberList.size());
//添加到上一页数据集合后面
mBlackNumberList.addAll(moreData);
//本次在添加的时候,不能进行下一次加载,下一次加载必须受到上一次加载完成的
isload = true;
//告知主线程,listV可以使用查询到的数据
mHandler.sendEmptyMessage(0);
};
}.start();
}
}
}
} public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) { }
});
} private void showDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final AlertDialog dialog = builder.create(); View view = View.inflate(this, R.layout.dialog_add_blacknumber, null); final EditText et_phone = (EditText) view.findViewById(R.id.et_phone); Button bt_submit = (Button) view.findViewById(R.id.bt_submit);
Button bt_cancel = (Button) view.findViewById(R.id.bt_cancel); RadioGroup rg_group = (RadioGroup) view.findViewById(R.id.rg_group); // 监听单选框的改变 (短信--电话--所有) rg_group.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(RadioGroup group, int checkedId) {
// 3,获取按钮组中选中的拦截类型
switch (checkedId) {
case R.id.rb_sms:
mode = 1;
break;
case R.id.rb_call:
mode = 2;
break;
case R.id.rb_all:
mode = 3;
break;
}
}
}); bt_submit.setOnClickListener(new OnClickListener() { public void onClick(View v) {
// 2,获取拦截电话电话号码
String phone = et_phone.getText().toString().trim();
// 4,插入数据库
mDao.insert(phone, mode);
// 5,创建一个BlacknumberInfo对象,将此对象更新到填充数据适配器的集合中去
BlackNumberInfo blackNumberInfo = new BlackNumberInfo();
blackNumberInfo.setMode(mode);
blackNumberInfo.setPhone(phone);
// 将提交的数据放在最上面
mBlackNumberList.add(0, blackNumberInfo); // 6,通知数据适配器刷新,刷新更改后的数据
mAdapter.notifyDataSetChanged(); dialog.dismiss();
}
}); bt_cancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
}); // 为了兼容低版本
dialog.setView(view, 0, 0, 0, 0); dialog.show();
}
} //附上数据库操作部分代码
继承SqliteOpenHelper类的帮助类此处省略
package cn.itae.listview_optimize.db.dao;

import java.util.ArrayList;
import java.util.List; import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import cn.itae.listview_optimize.db.BlackNumberOpenHelper;
import cn.itae.listview_optimize.db.domain.BlackNumberInfo; /**
* @author advance
* @E-mail:18943704697@163.com
* @qq:974467160 创建操作数据库中数据的一个单例对象
*/
public class BlackNumberDao {
private BlackNumberOpenHelper blackNumberOpenHelper; // 私有化构造方法
private BlackNumberDao(Context ctx) {
blackNumberOpenHelper = new BlackNumberOpenHelper(ctx);
} // 创建返回该类的对象
private static BlackNumberDao blackNumberDao = null; // 对外提供访问方法
public static BlackNumberDao getInstance(Context ctx) { if (blackNumberDao == null) {
blackNumberDao = new BlackNumberDao(ctx);
}
return blackNumberDao;
} // 提供访问数据库中数据的CRUD方法 /**
* @param phone
* 要添加黑名单的号码
* @param mode
* 选择黑名单的模式
*/
public void insert(String phone, int mode) {
// 获取数据操作对象
SQLiteDatabase db = blackNumberOpenHelper.getWritableDatabase(); ContentValues values = new ContentValues();
values.put("phone", phone);
values.put("mode", mode); // 由于要让后添加的黑名单号码显示在最前端,故按照id逆序排序
db.insert("blacknumber", null, values);
} /**
* @param phone
* 通过提供的号码去删除该黑名单
*/
public void delete(String phone) {
SQLiteDatabase db = blackNumberOpenHelper.getWritableDatabase(); db.delete("blacknumber", "phone = ?", new String[] { phone });
} /**
* @param phone
* 号码
* @param mode
* 黑名单类型 将指定的号码的黑名单类型改变
*/
public void update(String phone, int mode) {
SQLiteDatabase db = blackNumberOpenHelper.getWritableDatabase(); ContentValues values = new ContentValues();
values.put("mode", mode); db.update("blacknumber", values, "phone = ?", new String[] { phone });
} /**
* 一次查询20条
*
* @param index
* 查询的起始位置
*/
public List<BlackNumberInfo> find(int index) {
SQLiteDatabase db = blackNumberOpenHelper.getWritableDatabase();
List<BlackNumberInfo> blackNumberList = new ArrayList<BlackNumberInfo>(); // 依然要逆序查询,最后添加的数据,显示在最前面
String sql = "select phone,mode from blacknumber order by _id desc limit ?,20;";
Cursor cursor = db.rawQuery(sql, new String[] { index + "" }); // 将查询到的数据封装到javabean,再将javabean封装到集合中,方便去调用其中的数据
while (cursor.moveToNext()) {
BlackNumberInfo blackNumberInfo = new BlackNumberInfo(); blackNumberInfo.setPhone(cursor.getString(0));
blackNumberInfo.setMode(cursor.getInt(1)); blackNumberList.add(blackNumberInfo);
}
cursor.close();
db.close();
return blackNumberList;
} /**
* @return 返回数据库中的数据的总条数
*/
public int findTotalCount() {
int count = 0;
SQLiteDatabase db = blackNumberOpenHelper.getWritableDatabase(); String sql = "select count(*) from blacknumber;";
Cursor cursor = db.rawQuery(sql, null);
if (cursor.moveToNext()) {
// 获取总条目数
count = cursor.getInt(0);
}
cursor.close();
db.close();
return count;
}
}

  

//其他的selector选择器和布局文件此处省略....

结果图显示



  

ListView 的优化(原)的更多相关文章

  1. Android进阶笔记14:ListView篇之ListView性能优化

    1. 首先思考一个问题ListView如何才能提高效率 ? 当convertView为空时候,用setTag()方法为每个View绑定一个存放控件的ViewHolder对象.当convertView不 ...

  2. Android进阶笔记11:ListView篇之ListView性能优化

    1. 首先思考一个问题ListView如何才能提高效率 ? 当convertView为空时候,用setTag()方法为每个View绑定一个存放控件的ViewHolder对象.当convertView不 ...

  3. 【腾讯Bugly干货分享】跨平台 ListView 性能优化

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/FbiSLPxFdGqJ00WgpJ94yw 导语 精 ...

  4. Android之ListView性能优化——一行代码绑定数据——万能适配器

    如下图,加入现在有一个这样的需求图,你会怎么做?作为一个初学者,之前我都是直接用SimpleAdapter结合一个Item的布局来实现的,感觉这样实现起来很方便(基本上一行代码就可以实现),而且也没有 ...

  5. android技巧(二)listview的优化

    对于listview的优化有以下三个措施: 1.原有listview每一个item显示时都会调用一次getView()方法,实际上对于ListView而言,只需要保留能够显示的最大个数的view即可, ...

  6. Android Listview 性能优化

    首先我一般使用的适配器是BaseAdapter,其中有两个方法最主要,分别是: getCount,getView, 在对Listview 进行优化的时候,首先使用 convertview 和viewH ...

  7. BaseAdapter以及对ListView的优化(转)

    背景 对于ListView.GridView.Gallery.Spinner等等,它是它们的适配器,直接继承自接口类Adapter的,使用BaseAdapter时需要重写很多方法,其中最重要的当属ge ...

  8. ym——Android之ListView性能优化

    转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! Android之ListView性能优化 假设有看过我写过的15k面试题的朋友们一定知 ...

  9. Android实训案例(五)——四大组件之一ContentProvider的使用,通讯录的实现以及ListView的优化

    Android实训案例(五)--四大组件之一ContentProvider的使用,通讯录的实现 Android四大组件是啥这里就不用多说了,看图吧,他们之间通过intent通讯 我们后续也会一一的为大 ...

随机推荐

  1. How to Develop blade and soul Skills

    How to Develop Skills Each skill can be improved for variation effects. Some will boost more strengt ...

  2. web.config连接字符串的一些总结

    阅读目录: DS01:数据库连接字符串的两种写法 DS02:数据库连接字符串的内容 DS01:数据库连接字符串的两种写法 1.连接字符串的两种写法: <configuration>   & ...

  3. java给不同步的集合加上同步锁

    给非同步的集合加锁: class MyCollections{//创建工具类,提供对外访问方法 public static list synList(List list){ return new My ...

  4. MYSQL数据库日志和mysqlbinlog相关

    mysql有4种不同的日志,分别是二进制日志,查询日志,慢查询日志和错误日志,这些日记记录着数据库工作的方方面面,可以帮助我们了解数据库的不同方面的踪迹,下面介绍二进制日志的作用和使用方法. 1.二进 ...

  5. Bootstrap<基础十七>导航栏

    导航栏是一个很好的功能,是 Bootstrap 网站的一个突出特点.导航栏在您的应用或网站中作为导航页头的响应式基础组件.导航栏在移动设备的视图中是折叠的,随着可用视口宽度的增加,导航栏也会水平展开. ...

  6. Ubuntu上安装MySql过程,以及遇到的一些问题

    今天在Ubuntu服务器上安装MySql的时候遇到了一些问题,记录下来,以防以后忘记. 安装环境:Ubuntu14.04 安装命令: //安装Mysal服务端//会提示输入root密码 sudo ap ...

  7. maven添加自己的jar包到本地仓库

     mvn install:install-file -DgroupId=com.esotericsoftware -DartifactId=minlog -Dversion=1.2 -Dpackagi ...

  8. web app性能大讨论

    1.Application:应用,为用户完成一个或多个功能而设计的程序: 2.Internet or Intranet:运行于广域网或局域网之上: 3.Browser-supported langua ...

  9. 将word文件快速转换成表格的技巧

    最近烦心事还真是很多,世界买家网最近就遇到了很多烦心事. 从www.buyerinfo.biz网站中的数据导出为csv格式的文件,我导出了buyer的数据,那怎么把它制作成表格呢? 找了下,发现还是比 ...

  10. mysql 获取当前日期及格式化 (转)

    MYSQL 获取当前日期及日期格式获取系统日期: NOW()格式化日期: DATE_FORMAT(date, format)注: date:时间字段format:日期格式 返回系统日期,输出 2009 ...