关键字搜索

本文介绍了一种Android应用中的关键字搜索功能,包括按首字母排序、关键字检索、关键字高亮显示和实时更新。在实现过程中,由于不同数据库对关键字排序支持不一,作者采取了在内存中对模糊查询结果进行排序的解决方案,同时通过Limit优化大量数据的搜索性能。文章提供了实现思路和关键代码。

写这篇文章在半个月前就打算写,后来因为比较忙,赶项目,然后端午节回家一趟有事给耽误了,今天终于有时间可以补这个篇文章给补上了。 

首先说明这个功能要求:

1、首先能够根据数据的首字母进行排序显示,类似于通讯录一样;

2、能够在搜索栏输入关键字进行按关键它检索,并且按规定的顺序对关键字进行排序;

3、对搜索出来的数据包含关键的内容关键字进行高突出显示。

4、输入的关键字时时自动更新检索的内容


这个功能的来源:

由于用户数量比较多,简单的根据首字母来检索速度还是不够快,所以添加关键字自动检索功能,为了突出检索内容,所以将关键高亮显示。并且需要按关键字在内容中的位置先后顺序来进行排序。


没有动手做之前,开始以为这个按关键字在内容在的位置排序是可以通过sql语句来实现的。。。确实是可以通过sql语句实现,但这只是部分数据库可以支持。这也是接下来进走过的哪些坑。

MySql数据库有直接实现的函数,而oracle和sqlite数据库也有,对,没错,android支持的sqlite数据库也有,但是。。。只是5.0及以上的版本支持,有个instr函数,直接order by就可以实现这个小功能,但是5.0以前的版本呢???所以不得不换一个实现方式。后来没有办法只能先把数据按关键字模糊查询出来,然后再按规则进行在内存中进行排序,这样就解决了这个问题。但是当时没有考虑数据多的情况,到后现发现,数据量一多,模糊查询,尤其是%%这种查询真是慢的要死骂人。没有办法只能又想了一个投机的办法,我给他来个limit,这时瞬间就好了,因为输入的数据是手机号码,全中国的移动手机号码都是1开头的,一个通讯录里面1开头的电话号码该有百分之九十吧。所以来个Limit不管你了,输的关键字越多结果越少。


好了,先给大家看下实现效果图吧





上面基本上把要实现的,如何实现的思路都大概讲下,下面开始讲具体实现以及重要方法代码给贴出来。

获取内容首字母的拼音方法

public static String getPinYinHeadChar(String str) {
		String convert = "";
		for (int j = 0; j < str.length(); j++) {
			char word = str.charAt(j);
			String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);
			if (pinyinArray != null) {
				convert += pinyinArray[0].charAt(0);
			} else {
				convert += word;
			}
		}
		return convert;
	}

按名字的首字母进行排序方法

new Thread(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub

				Collections.sort((List) customList,
						new Comparator<CustomForm>() {

							@Override
							public int compare(CustomForm lhs, CustomForm rhs) {
								// 0为等于,1大于,-1小于
								if (getPinYinHeadChar(lhs.getName()).charAt(0) > getPinYinHeadChar(
										rhs.getName()).charAt(0))
									return 1;
								else if (getPinYinHeadChar(lhs.getName())
										.charAt(0) < getPinYinHeadChar(
										rhs.getName()).charAt(0))
									return -1;
								return 0;
							}
						});
				historyList.add(customList);
				handler.sendEmptyMessage(0);
			}
		}).start();


关键字快速排序算法

	/**
	 * 快速排序
	 * 
	 * @param n
	 * @param left
	 * @param right
	 */
	static void quicksort(ArrayList<CustomSortBean> n, int left, int right) {
		int dp;
		if (left < right) {
			dp = partition(n, left, right);
			quicksort(n, left, dp - 1);
			quicksort(n, dp + 1, right);
		}
	}

	/**
	 * 快速排序找出中间标号
	 * 
	 * @param n
	 * @param left
	 * @param right
	 * @return
	 */
	static int partition(ArrayList<CustomSortBean> n, int left, int right) {
		CustomSortBean pivot = n.get(left);
		while (left < right) {
			while (left < right
					&& n.get(right).getPosition() >= pivot.getPosition())
				right--;
			n.set(left, n.get(right));
			while (left < right
					&& n.get(left).getPosition() <= pivot.getPosition())
				left++;
			n.set(right, n.get(left));
		}
		n.set(left, pivot);
		return left;
	}
通过将列表按具体规则调用快排进行排序

/**
	 * 将获取的List进行排序
	 * 
	 * @param customList
	 * @param key
	 * @return
	 */
	public ArrayList<CustomForm> sortList(ArrayList<CustomForm> customList,
			String key) {
		ArrayList<CustomForm> list = new ArrayList<CustomForm>();
		ArrayList<CustomSortBean> index = new ArrayList<CustomSortBean>();
		for (int i = 0; i < customList.size(); i++) {
			CustomSortBean bean = new CustomSortBean();
			bean.setIndex(i);
			if (customList.get(i).getMobile().indexOf(key) > -1) {// 手机号码优先
				bean.setPosition(customList.get(i).getMobile().indexOf(key));
			} else if (customList.get(i).getName().indexOf(key) > -1) {// 名字其次
				int po = (customList.get(i).getName().indexOf(key) + 1) * 200
						+ i;// 体现位置的顺序大于本来顺序
				bean.setPosition(po);
			} else {
				if (customList.get(i).getVillage() != null) {// 村组最后
					int po = (customList.get(i).getVillage().indexOf(key) + 2)
							* 400 + i;
					bean.setPosition(po);
				}
			}
			index.add(bean);
		}
		quicksort(index, 0, index.size() - 1);
		for (int i = 0; i < index.size(); i++) {

			list.add(customList.get(index.get(i).getIndex()));
		}
		return list;
	}

关键字高亮显示的自定义View,需要使用SpannableStringBuilder方法来实现:

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
import android.widget.TextView;

public class SpannableTextView extends TextView {

	public SpannableTextView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public void setSpecifiedTextsColor(String text, String specifiedTexts,
			int color) {
		List<Integer> sTextsStartList = new ArrayList<Integer>();
		specifiedTexts = specifiedTexts.toLowerCase();
		int sTextLength = specifiedTexts.length();
		String temp = text.toLowerCase();
		int lengthFront = 0;// 记录被找出后前面的字段的长度
		int start = -1;
		do {
			start = temp.indexOf(specifiedTexts);

			if (start != -1) {
				start = start + lengthFront;
				sTextsStartList.add(start);
				lengthFront = start + sTextLength;
				temp = text.substring(lengthFront);
			}
		} while (start != -1);

		SpannableStringBuilder styledText = new SpannableStringBuilder(text);
		for (Integer i : sTextsStartList) {
			styledText.setSpan(new ForegroundColorSpan(color), i, i
					+ sTextLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		}

		setText(styledText);
	}

}


输入内容进行自动检索方法直接覆写editetext的addTextChangedListener方法即可。

如果看不明白的,或者需要代码来理解了,我可以为大家整理一套简单的demo。欢迎大家来骚扰





评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值