在上一篇中实现了,先自定义数据源,使Adapter通过实现SectionIndexer接口给ListView分组,并用Collections.sort对数据list进行排序。
但是Collections.sort并不高效,如果数据源太多,必然会太耗时,所以这篇使用android.widget.Filterable自动筛选城市。
Filterable定义了一种可过滤的行为:
protected FilterResults performFiltering(CharSequence prefix)方法定义过滤条件
protected void publishResults(CharSequence constraint, FilterResults results)发布筛选过后得到的数据同时更新Adapter更新。
这篇代码是在上一篇的基础上改造的,就多了SearchCityAdapter(使用了Filterable)和city.db以及一些数据库操作的类。先看一下源码结构目录(去掉了CharacterParser(汉字转换成拼音的类)和Collections.sort方法):
上几张运行截图效果:
先看SearchCityAdapter:
public class SearchCityAdapter extends BaseAdapter implements Filterable {
private List mAllCities;
private List mResultCities;
private LayoutInflater mInflater;
private Context mContext;
// private String mFilterStr;
public SearchCityAdapter(Context context, List allCities) {
mContext = context;
mAllCities = allCities;
mResultCities = new ArrayList();
mInflater = LayoutInflater.from(mContext);
}
@Override
public int getCount() {
return mResultCities.size();
}
@Override
public City getItem(int position) {
return mResultCities.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.search_city_item, null);
}
TextView provinceTv = (TextView) convertView
.findViewById(R.id.search_province);
provinceTv.setText(mResultCities.get(position).getProvince());
TextView cityTv = (TextView) convertView
.findViewById(R.id.column_title);
cityTv.setText(mResultCities.get(position).getCity());
return convertView;
}
@Override
public Filter getFilter() {
Filter filter = new Filter() {
protected void publishResults(CharSequence constraint,
FilterResults results) {
mResultCities = (ArrayList) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
protected FilterResults performFiltering(CharSequence s) {
String str = s.toString().toUpperCase();
// mFilterStr = str;
FilterResults results = new FilterResults();
ArrayList cityList = new ArrayList();
if (mAllCities != null && mAllCities.size() != 0) {
for (City cb : mAllCities) {
// 匹配全屏、首字母、和城市名中文
if (cb.getAllFristPY().indexOf(str) > -1
|| cb.getAllPY().indexOf(str) > -1
|| cb.getCity().indexOf(str) > -1) {
cityList.add(cb);
}
}
}
results.values = cityList;
results.count = cityList.size();
return results;
}
};
return filter;
}
}
通过
if (mAllCities != null && mAllCities.size() != 0) {
for (City cb : mAllCities) {
// 匹配全屏、首字母、和城市名中文
if (cb.getAllFristPY().indexOf(str) > -1
|| cb.getAllPY().indexOf(str) > -1
|| cb.getCity().indexOf(str) > -1) {
cityList.add(cb);
}
}
}
results.values = cityList;
results.count = cityList.size();
return results;
protected void publishResults(CharSequence constraint,
FilterResults results) {
mResultCities = (ArrayList) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
中,如果过滤得到的
results非空,则调用notifyDataSetChanged方法强制调用getView来刷新每个Item的内容。否则调用notifyDataSetInvalidated()会重绘View。
mSearchListView.setEmptyView(findViewById(R.id.search_empty));
listView.setEmptyView(findViewById(R.id.citys_list_load));
最后再来看看LetterSortActivity:
public class LetterSortActivity extends Activity implements OnClickListener {
public static final String TAG = LetterSortActivity.class.getSimpleName();
private Context context = LetterSortActivity.this;
private ClearEditText mClearEditText;
private TextView tv_mid_letter;
private ListView listView;
private MyLetterSortView right_letter;
private ItemBeanAdapter mAdapter;
private List mlist = new ArrayList();
private InputMethodManager inputMethodManager;
private View mCityContainer;
private FrameLayout mSearchContainer;
private ListView mSearchListView;
private SearchCityAdapter mSearchCityAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
initView();
setLinstener();
initData();
fillData();
}
protected void initData() {
getDataCity();
mAdapter = new ItemBeanAdapter(this, mlist);
listView.setEmptyView(findViewById(R.id.citys_list_load));
listView.setAdapter(mAdapter);
}
protected void initView() {
inputMethodManager = (InputMethodManager) this
.getSystemService(Context.INPUT_METHOD_SERVICE);
listView = (ListView) findViewById(R.id.list);
mClearEditText = (ClearEditText) findViewById(R.id.et_msg_search);
// 这里设置中间字母
right_letter = (MyLetterSortView) findViewById(R.id.right_letter);
tv_mid_letter = (TextView) findViewById(R.id.tv_mid_letter);
right_letter.setTextView(tv_mid_letter);
//搜索
mCityContainer = findViewById(R.id.city_content_container);
mSearchContainer = (FrameLayout) this.findViewById(R.id.search_content_container);
mSearchListView = (ListView) findViewById(R.id.search_list);
mSearchListView.setEmptyView(findViewById(R.id.search_empty));
mSearchContainer.setVisibility(View.GONE);
}
protected void setLinstener() {
// tv_reget_pwd.setOnClickListener(this);
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
T.showShort(getApplicationContext(),
((City) mAdapter.getItem(position)).toString());
}
});
listView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// 隐藏软键盘
if (getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
if (getCurrentFocus() != null)
inputMethodManager.hideSoftInputFromWindow(
getCurrentFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
}
return false;
}
});
// 设置右侧触摸监听
right_letter
.setOnTouchingLetterChangedListener(new OnTouchingLetterChangedListener() {
@Override
public void onTouchingLetterChanged(String s) {
// 该字母首次出现的位置
int position = mAdapter.getPositionForSection(s
.charAt(0));
if (position != -1) {
listView.setSelection(position);
}
}
});
// 根据输入框输入值的改变来过滤搜索
mClearEditText.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
// 当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表
filterData2(s.toString());
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
mSearchListView
.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
// L.i(mSearchCityAdapter.getItem(position).toString());
T.showLong(getApplicationContext(), mSearchCityAdapter
.getItem(position).toString());
}
});
}
protected void fillData() {
// TODO Auto-generated method stub
}
private void getDataCity() {
new Thread(new Runnable() {
@Override
public void run() {
MyCityDBHelper myCityDBHelper = new MyCityDBHelper(context);
mlist = myCityDBHelper.getCityDB().getAllCity();
mHandler.sendEmptyMessage(0);
}
}).start();
// 对list进行排序
// Collections.sort(mlist, new PinyinComparator() {
// });
}
private void filterData2(String filterStr) {
mSearchCityAdapter = new SearchCityAdapter(LetterSortActivity.this,
mlist);
mSearchListView.setAdapter(mSearchCityAdapter);
mSearchListView.setTextFilterEnabled(true);
if (mlist.size() < 1 || TextUtils.isEmpty(filterStr)) {
mCityContainer.setVisibility(View.VISIBLE);
mSearchContainer.setVisibility(View.INVISIBLE);
} else {
mCityContainer.setVisibility(View.INVISIBLE);
mSearchContainer.setVisibility(View.VISIBLE);
mSearchCityAdapter.getFilter().filter(filterStr);
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
//
default:
break;
}
}
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 0:
mAdapter.updateListView(mlist);
break;
default:
break;
}
}
};
}
另一个修改的地方就是filterData()方法了,这里主要是mSearchCityAdapter.getFilter().filter(filterStr);把过滤条件交给它就OK了。
当然,你仍然可以像上一篇中那样先筛选数据,再使用Collections.sort排序,最后更新ListView。代码如下:
private void filterData(String filterStr) {
List filterDateList = new ArrayList();
if (TextUtils.isEmpty(filterStr)) {
mAdapter.updateListView(mlist);
} else {
filterDateList.clear();
for (City city : mlist) {
String name = city.getCity();
if (name != null) {
if (name.indexOf(filterStr.toString()) != -1
|| CharacterParser.getInstance().getSelling(name)
.startsWith(filterStr.toString())) {
filterDateList.add(city);
}
}
}
Collections.sort(filterDateList, new PinyinComparator() {
});
mAdapter.updateListView(filterDateList);
}
}
你还可以这样尝试:
查询数据库的时候Cursor c = db.rawQuery("SELECT * from " + CITY_TABLE_NAME, null);
不使用order by 。然后再通过Collections.sort排序,哇咔咔,要好几秒啊才能把城市数据列表加载出来啊,没办法,数据有点多。
就写到这里吧!
DEMO下载地址:http://download.csdn.net/detail/yalinfendou/8616375