從 ContactsContract 查詢聯系人姓名顯示在 TextView 時,中文顯示為「???」或亂碼,英文正常。
聯系人數據庫中姓名欄位可能存儲為 **BLOB 二進制格式**(歷史兼容性),直接用 getString() 讀取會按默認編碼解析導致亂碼。需先 getBlob() 取得原始字節,再指定 **UTF-8** 解碼。
// 查詢游標
Cursor cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI,
new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME},
null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
int nameIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
// 關鍵:getBlob + UTF-8 解碼 + 清理控制字符
byte[] nameBytes = cursor.getBlob(nameIndex);
String name = new String(nameBytes, StandardCharsets.UTF_8)
.replace("\u0000", "") // 移除空字符
.replace("\r", ""); // 移除回車符
textView.setText(name);
}
cursor.close();
}
public static String getContactNameSafe(Cursor cursor, int columnIndex) {
if (cursor == null || columnIndex < 0) return "";
byte[] blob = cursor.getBlob(columnIndex);
if (blob == null || blob.length == 0) return "";
try {
return new String(blob, StandardCharsets.UTF_8)
.replace("\u0000", "")
.replace("\r", "")
.trim();
} catch (Exception e) {
// 兜底:嘗試默認解碼
return cursor.getString(columnIndex);
}
}
fun Cursor.getContactName(columnName: String): String {
val index = getColumnIndex(columnName)
return if (index >= 0) {
getBlob(index)?.let { bytes ->
String(bytes, Charsets.UTF_8)
.replace("\u0000", "")
.replace("\r", "")
.trim()
} ?: getString(index) // fallback
} else ""
}
// 使用 ContactsContract.CommonDataKinds.StructuredName 獲取結構化姓名 (較新 API)
String[] projection = {
StructuredName.DISPLAY_NAME,
StructuredName.GIVEN_NAME,
StructuredName.FAMILY_NAME
};
Cursor c = resolver.query(Data.CONTENT_URI, projection,
Data.MIMETYPE + "=?", new String[]{StructuredName.CONTENT_ITEM_TYPE}, null);
// 此路徑通常直接返回 String,較少亂碼
Android 聯系人中文亂碼核心在於 **BLOB 字段需手動指定 UTF-8 解碼**。採用 cursor.getBlob(index) → new String(bytes, UTF-8) 模式並清理控制字符(\u0000, \r),可 100% 解決顯示異常。建議封裝為工具方法,全專案統一調用。