今天用了整整一下午去捣鼓这块,为 什么模拟器上可以按拼音排序,中英文混排,及按字母搜索联系人,但到了开发板(平台是根据 android2.2 改过的)上就怎么不行了呢,虽然现 在还没有解决,但也是知道了问题所在,离解决之路也就不远了
好吧, 现在就解释下 android2.2 是怎么按拼音排序的。
首先我 们来看下 android.2 自带通讯录的数据库文件 contacts2.db 的 raw_contacts 表。用 sqlitedbviewer 工具打开后可以看到有这么一个字 段: sort_key ( sort_key_alt 与之相似,只不过是英文环境下有个按 given name 还是 first name 排序的问题)。
正常状况下,我们新建一个联系人的话,如果是英文,则 sort_key 与 display_name 字段显示相同,如果输入姓名是中 文,如“你好”, sort_key 则会显示“ ni 你 hao 好”,这样开发者既可以根据此字段 按拼音排序,中英文混排,以及按拼音搜索联系人拉。
现在就说下, android 是如何将中文名的联系人转化为拼音存 到 sort_key 里面的:
- if (displayNameStyle == FullNameStyle.CHINESE ||
- displayNameStyle == FullNameStyle.CJK) {
- sortKeyPrimary = sortKeyAlternative =
- ContactLocaleUtils.getIntanc).getSortKe(displayNamePrimary, displayNameStyle);}
- if
- (displayNameStyle == FullNameStyle.CHINESE ||
- displayNameStyle == FullNameStyle.CJK) {
- sortKeyPrimary = sortKeyAlternative =
- ContactLocaleUtils.getIntanc).getSortKe(displayNamePrimary,
- displayNameStyle);}
这段代码是运行在 contactsprovi2.Java 的 updateRawContactDisplayName() 方法里面,这段代码我们用到了 ContactLocaleUtils.java这个类,所以我们进入它以后最显眼的就是 ChineseContactUtils 这个 ContactLocaleUtils 的子类,它重写了 ContactLocaleUtils 的getSortKey ()方法,如下:
- public String getSortKey(String displayName) {
- ArrayList<Token> tokens = HanziToPinyin.getInstance().get(displayName);
- if (tokens != null && tokens.size() > 0 ) {
- StringBuilder sb = new StringBuilder();
- for (Token token : tokens) {
- // Put Chinese character's pinyin, then proceed with the
- // character itself.
- if (Token.PINYIN == token.type) {
- if (sb.length() > 0 ) {
- sb.append(' ' );
- }
- sb.append(token.target);
- sb.append(' ' );
- sb.append(token.source);
- } else {
- if (sb.length() > 0 ) {
- sb.append(' ' );
- }
- sb.append(token.source);
- }
- }
- return sb.toString();
- }
- return super .getSortKey(displayName);
- }
- public
- String getSortKey(String displayName) {
- ArrayList<Token> tokens =
- HanziToPinyin.getInstance().get(displayName);
- if (tokens != null && tokens.size() > 0) {
- StringBuilder sb = new StringBuilder();
- for (Token token : tokens) {
- // Put Chinese character's pinyin, then proceed with
- the
- // character itself.
- if (Token.PINYIN == token.type) {
- if (sb.length() > 0) {
- sb.append(' ');
- }
- sb.append(token.target);
- sb.append(' ');
- sb.append(token.source);
- } else {
- if (sb.length() > 0) {
- sb.append(' ');
- }
- sb.append(token.source);
- }
- }
- return sb.toString();
- }
- return super.getSortKey(displayName);
- }
首先我们看 ArrayList<Token> tokens = HanziToPinyin.getInstance().get(displayName); ,因为其他的无非就是插入格式的问题,我们暂时不用看。
android 如何 将汉字转为拼音的?这就用到了 HanziToPinyin 这个 类,好吧,我们先看下 HanziToPinyin 的 getInstance() 方法:
- public static HanziToPinyin getInstance() {
- synchronized (HanziToPinyin. class ) {
- if (sInstance != null ) {
- return sInstance;
- }
- // Check if zh_CN collation data is available
- final Locale locale[] = Collator.getAvailableLocales();
- for ( int i = 0 ; i < locale.length; i++) {
- if (locale[i].equals(Locale.CHINA)) {
- sInstance = new HanziToPinyin( true );
- return sInstance;
- }
- }
- Log.w(TAG, "There is no Chinese collator, HanziToPinyin is disabled" );
- sInstance = new HanziToPinyin( false );
- return sInstance;
- }
- }
- public static HanziToPinyin getInstance() {
- synchronized(HanziToPinyin.class) {
- if (sInstance != null) {
- return sInstance;
- }
- // Check if zh_CN collation data is available
- final Locale locale[] = Collator.getAvailableLocales();
- for (int i = 0; i < locale.length; i++) {
- if (locale[i].equals(Locale.CHINA)) {
- sInstance = new HanziToPinyin(true);
- return sInstance;
- }
- }
- Log.w(TAG, "There is no Chinese collator, HanziToPinyin is
- disabled");
- sInstance = new HanziToPinyin(false);
- return sInstance;
- }
- }
现在说下我的开发板为什么不能 转拼音;就是因为 final Locale locale[] = Collator.getAvailableLocales() 的 Locale 没有一项equals(Locale.CHINA) ,所以到时候解决了这项,联系人的按拼音排序也就解决了,如果大家不想用系统自带的,自己可以下载 个 pinyin4j.jar 包自己实现吧。
好吧,继续:
看方法名也只到,这个方法返回 一个 HanziToPinyin 实例,我仔细研究了 HanziToPinyin 的构造方法,无论纯如的布尔值是 false 还是 true 都不影响,返回的都一样,只不过这个方法的 Log.w(TAG, "There is no Chinese collator, HanziToPinyin is disabled"); 可以提示是否支持汉字转拼音,如果不能, android 就会将 displayname 原封不动的插入 sort_key 里面,如果能,就是刚才我说的 如“你好”, sort_key 则会显示“ ni 你 hao 好” ,这种形式,具体的如何转拼音就是 get ()方法拉,直接插代码:
- public ArrayList<Token> get( final String input) {
- ArrayList<Token> tokens = new ArrayList<Token>();
- if (!mHasChinaCollator || TextUtils.isEmpty(input)) {
- // return empty tokens.
- return tokens;
- }
- final int inputLength = input.length();
- final StringBuilder sb = new StringBuilder();
- int tokenType = Token.LATIN;
- // Go through the input, create a new token when
- // a. Token type changed
- // b. Get the Pinyin of current charater.
- // c. current character is space.
- for ( int i = 0 ; i < inputLength; i++) {
- final char character = input.charAt(i);
- if (character == ' ' ) {
- if (sb.length() > 0 ) {
- addToken(sb, tokens, tokenType);
- }
- } else if (character < 256 ) {
- if (tokenType != Token.LATIN && sb.length() > 0 ) {
- addToken(sb, tokens, tokenType);
- }
- tokenType = Token.LATIN;
- sb.append(character);
- } else if (character < FIRST_UNIHAN) {
- if (tokenType != Token.UNKNOWN && sb.length() > 0 ) {
- addToken(sb, tokens, tokenType);
- }
- tokenType = Token.UNKNOWN;
- sb.append(character);
- } else {
- Token t = getToken(character);
- if (t.type == Token.PINYIN) {
- if (sb.length() > 0 ) {
- addToken(sb, tokens, tokenType);
- }
- tokens.add(t);
- tokenType = Token.PINYIN;
- } else {
- if (tokenType != t.type && sb.length() > 0 ) {
- addToken(sb, tokens, tokenType);
- }
- tokenType = t.type;
- sb.append(character);
- }
- }
- }
- if (sb.length() > 0 ) {
- addToken(sb, tokens, tokenType);
- }
- return tokens;
- }