ListView 的优化(原)

时间:2023-03-09 21:46:45
ListView 的优化(原)

随着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 的优化(原)


ListView 的优化(原)