随着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选择器和布局文件此处省略....


结果图显示





  

posted on 2015-08-06 00:27  ADVANCE_ae  阅读(257)  评论(0编辑  收藏  举报