說到中國人的名字,那就不得不考慮多音字的問題,好比'單',在做爲姓氏時應該讀做'shan'而不是'dan'.可是在Contacts程序中卻使用的是'D'來做爲bucket label!
這是爲何?如何解決這種多音字姓氏的問題?
從4.3版本開始,HanziToPinyin.java(ContactsProvider中)改成直接調用ICU的Transliterator來對漢字進行transliterate(詳見類中mPinyinTransliterator變量的使用).咱們知道,ICU中的Han_Latin_Names.txt中保存了一些漢字在做爲姓氏時的讀音,若是在建立Transliterator對象時使用Han-Latin/Names做爲id(可參考mPinyinTransliterator變量的初始化),將能夠正確的得到漢字做爲姓氏時的讀音(僅限於Han_Latin_Names.txt中包含的漢字).也就是說,HanziToPinyin這個類在處理做爲姓氏的多音字時是能夠得到正確得到其讀音的.如在使用HanziToPinyin獲取'單田芳'的讀音爲'shan tian fang'.就算這樣姓名爲'單田芳'的聯繫人依然被排在'D'下面!這是爲何呢?
經過解析代碼能夠發現,聯繫人排在哪一個字母下面是由raw_contacts表中的phonebook_label的值來決定的,而數據庫中phonebook_label的值確實是'D',主要是由於在得到phonebook_label時使用的是AlphabeticIndex$ImmutableIndex的getBucketLabel函數,而這個函數是沒有對姓氏多音字作任何特殊處理的,因此最後獲得的是'D'(phonebook_label的處理流程見附一).
目前,若是想比較省力的解決這個問題,能夠在獲取phonebook_label時避免經過使用AlphabeticIndex$ImmutableIndex的getBucketLabel函數來獲取,而是改成用HanziToPinyin去得到sortKeyPrimary的第一個字符的拼音(sortKeyAlternative暫不考慮).
貼一下代碼修改(基於4.4.4_r2)
-----------------------------------------------------------------------------
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -78,6 +78,7 @@ import android.text.util.Rfc822Tokenizer;
import android.util.Log;
import com.android.common.content.SyncStateContentProviderHelper;
+import com.android.providers.contacts.HanziToPinyin.Token;
import com.android.providers.contacts.aggregation.util.CommonNicknameCache;
import com.android.providers.contacts.database.ContactsTableUtil;
import com.android.providers.contacts.database.DeletedContactsTableUtil;
@@ -85,6 +86,7 @@ import com.android.providers.contacts.database.MoreDatabaseUtils;
import com.android.providers.contacts.util.NeededForTesting;
import com.google.android.collect.Sets;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Set;
@@ -5388,8 +5390,25 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper {
ContactLocaleUtils localeUtils = ContactLocaleUtils.getInstance();
if (sortKeyPrimary != null) {
- phonebookBucketPrimary = localeUtils.getBucketIndex(sortKeyPrimary);
- phonebookLabelPrimary = localeUtils.getBucketLabel(phonebookBucketPrimary);
+ boolean flag = false;
+ if (displayNameStyle == FullNameStyle.CHINESE
+ && HanziToPinyin.getInstance().hasChineseTransliterator()) {
+ String target = sortKeyPrimary.substring(0, 1);
+ ArrayList<Token> tokens = HanziToPinyin.getInstance().get(target);
+ if (tokens != null && tokens.size() > 0) {
+ char label = tokens.get(0).target.charAt(0);
+ if (label >= 'A' && label <= 'Z') {
+ phonebookLabelPrimary = String.valueOf(label);
+ phonebookBucketPrimary = localeUtils.getBucketIndex(phonebookLabelPrimary);
+ flag = true;
+ }
+ }
+ }
+
+ if (!flag) {
+ phonebookBucketPrimary = localeUtils.getBucketIndex(sortKeyPrimary);
+ phonebookLabelPrimary = localeUtils.getBucketLabel(phonebookBucketPrimary);
+ }
}
if (sortKeyAlternative != null) {
phonebookBucketAlternative = localeUtils.getBucketIndex(sortKeyAlternative);java
-----------------------------------------------------------------------------
經過上面的分析能夠發現一個問題,那就是在Contacts主頁面用'dan tian fang'搜索聯繫人時是搜不到的,只能用'shan tian fang'來搜索,可是在顯示時確是將該聯繫人放在了'D'分組下面!根本緣由就是NameLookupBuilder在調用 appendNameShorthandLookup時實際上使用了HanziToPinyin來獲取讀音,這時獲得的是做爲姓氏時的讀音,而 phonebook_label是使用AlphabeticIndex$ImmutableIndex的getBucketLabel函數來獲取的,而它 沒有對姓氏多音字作任何特殊處理,這就致使了前面說的問題.
另外,用HanziToPinyin的一個問題是全部的可做爲姓氏的漢字的讀音都是姓氏的讀音,如'單位單'的拼音是'shan wei shan'.如何解決這個問題呢?其實現有條件下沒有一個好的辦法(加詞庫的方法除外),只能儘可能規避.個人方法是中文狀況下名字中的第一個漢字做爲姓氏去獲取讀音(使用Han-Latin/Names; Latin-Ascii; Any-Upper建立的Transliterator對象),而其它漢字則做爲普通漢字去獲取讀音(使用Han-Latin; Latin-Ascii; Any-Upper建立的Transliterator對象,需在HanziToPinyin中再新建一個Transliterator對象).
附一
raw_contacts表中的phonebook_label的獲取流程:
raw_contacts表中的phonebook_label是經過調用ContactsDatabaseHelper的updateRawContactDisplayName函數來完成插入/更新的.使用的是phonebookLabelPrimary變量的值.而phonebookLabelPrimary是ContactLocaleUtils中getBucketLabel得到的,getBucketLabel中實際調用的是ICU中ImmutableIndex的getBucketLabel來完成的().android