0、相關文章
Android中的string資源佔位符及Plurals string
1、使用
對一個給定的語言和數字來說,決定使用哪一個case的規則是很複雜的,所以android提供了方法getQuantityString(),它可以用來爲你選擇合適的資源。
一個複數或者單數字符串。它的值可以是對其他字符串資源的一個引用。必須是 的子節點。必須知道不要撇號和引號。可以參考下面的例子。
屬性:
quantity:
關鍵字.這個值反應了什麼時候這個字符該被使用。正確的值,在括號裏面有不詳盡的例子:
Value
zero 當語言需要特別對待0時(就想阿拉伯)
one 當語言需要特別對待1(就像英語裏和其他語言裏的1;在russian,任何以1結尾但是不是以11結尾的也使用這種情況)
two 當語言需要特別對待1(例如Welsh的2,或者Slovenian的102)
few 當語言需要特別對待small(例如Czech的2,3,4;或者以2,3,4結尾但是不是12,13,14的Polisth)
many 當語言需要特別對待large(例如Maltese的11-99)
other 當語言沒有要求對特定資
實例:
<plurals name="book_number" >
<item quantity="one">%d book</item>
<item quantity="other">%d books</item>
</plurals>
代碼:
String bookNum = getResources().getQuantityString(R.plurals.book_number, 1, 2);
tv4.setText(bookNum);
String bookNum2 = getResources().getQuantityString(R.plurals.book_number, 2, 4);
tv5.setText(bookNum2);
注意:一定要在English語言環境下才起作用,語言爲中文不起效。
當第二個參數爲1時,會調用 book,爲其他數值時,會調用books。
爲什麼只在英文語言環境下才起作用呢?
2、源碼分析
@NonNull
public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
throws NotFoundException {
//容易看出,先根據quantity決定要使用的字符串
String raw = getQuantityText(id, quantity).toString();
//再進行佔位符的替換工作
return String.format(mResourcesImpl.getConfiguration().getLocales().get(0), raw,
formatArgs);
}
@NonNull
public CharSequence getQuantityText(@PluralsRes int id, int quantity)
throws NotFoundException {
//依賴於ResourceImpl的實現
return mResourcesImpl.getQuantityText(id, quantity);
}
跟進ResourceImpl中的getQuantityText函數:
CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException {
//得到規則
PluralRules rule = getPluralRule();
//rule.select根據規則,得到quantity對應的QuanitiyCode,即"zero"、"one"、"other"等
//之後再根據QuanitiyCode,的到具體的資源文件
CharSequence res = mAssets.getResourceBagText(id,
attrForQuantityCode(rule.select(quantity)));
if (res != null) {
return res;
}
//rule沒能找到對應的QuanitiyCode時,就用"other"字段的定義
res = mAssets.getResourceBagText(id, ID_OTHER);
if (res != null) {
return res;
}
//上面尋找資源文件出問題,就拋出異常
throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
+ " quantity=" + quantity
+ " item=" + rule.select(quantity));
}
這裏我們首先看一下getPluralRule函數:
private PluralRules getPluralRule() {
synchronized (sSync) {
if (mPluralRule == null) {
//單例模式,且和本地化有關,以Locales的第一個配置來初始化規則
mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
}
return mPluralRule;
}
}
PluralRules的select函數對應的底層實現,在此不作深研究,不同的Locales應該有不同的實現。
在此看看attrForQuantityCode:
private static int attrForQuantityCode(String quantityCode) {
switch (quantityCode) {
case PluralRules.KEYWORD_ZERO: return 0x01000005;
case PluralRules.KEYWORD_ONE: return 0x01000006;
case PluralRules.KEYWORD_TWO: return 0x01000007;
case PluralRules.KEYWORD_FEW: return 0x01000008;
case PluralRules.KEYWORD_MANY: return 0x01000009;
default: return ID_OTHER;
}
}
從上面的代碼可以看出,PluralRules的select函數的作用,就是將quantity映射成PluralRules定義的Keyword。
然後attrForQuantityCode將Keyword轉化成資源文件能識別的標誌。
現在回到我們之前的問題,爲什麼終端語言爲中文時,Plurals string失效?
原因是attrForQuantityCode的結果一直是ID_OTHER,即中文對應PluralRules無法有效將Quantity轉化爲正確的Keyword。
當然,Google的這種設計並不是Bug,畢竟中文語言環境下,App的顯示就應該是中文,本來就沒有這種需求。