本文按照遇到问题的思路展开:

(一) 在Res下String.xml向字符串中插入“&”符号报错

如下图所示:

翻译:在对实体的引用中,实体名必须紧跟在“&”后。

查找知道:这设计到HTML语言的字符集知识:

在网页中除了可显示常见的ASCII字符和汉字外,HTML还有许多特殊字符,它们一起构成了HTML字符集。有2种情况需要使用特殊字符,一是网页中有其特殊意义的字符,二是键盘上没有的字符。 字符集HTML字符可以用一些代码来表示,代码可以有2种表示方式。即字符代码(命名实体)和数字代码(编号实体)。字符代码以&符开始,以分号结束,其间是字符名;数字代码也以&符开始,以分号结束,其间是#号加编号。示例见下图,完整的html字符集在文后Excel附件中,并非全部,仅常用。

(二) 这涉及到了Android对此有专门的处理

文档中有专门说明,如下图所示:

字符串可以包含风格标签(styling tag),需要注意的是:你必须转码(escaping)缩写号( apostrophe即’)和引用号(quotation mark 即”或’)。你可风格化(style)和格式化(format)字符串。

1, 对缩写号和引号的处理

文档示例如下:

正确的转码是:

A:用双引号将字符串全部圈住

B:使用转义符号“\

错误做法:

A:不处理

错误如下图所示:

正确方法见上正确转码

B:使用html的字符代码代替缩写号

错误如下图所示:

对以上错误的修正:

Note:因为xml并不是完全实时编译,所以可以错误的xml语句并不当时报错,但当项目启动时,会报错。

2, 格式化字符串(format string)

即字符串中保留参数位作为模板,可以传入变量,转换。eg,SimpleDateFormat

模板为:yyyy-MM-dd,传入Date,得到1999-10-10

String.xml文件中代码如下:

 
    
  1. <string name="welcome_messages">Hello, %1$s! You have %2$d new messages.string> 

Java中代码如下:

 
    
  1. Resources res = getResources(); 
  2. String text = String.format(res.getString(R.string.welcome_messages), username, mailCount); 

有必要说明的是:

%:产生字面值,貌似是这个意思。

1$:代表第一个参数

2$:代表第二个参数

s:参数类型是字符串

d:参数类型是数字

More:http://dlc.sun.com.edgesuite.net/jdk/jdk-api-localizations/jdk-api-zh-cn/builds/latest/html/zh_CN/api/java/util/Formatter.html#syntax

Java代码如下:

3, 在字符串中使用Html标记风格符号(Html makeup)

即Html的字符代码。一步一步,终于排除到问题的可能解答处。

1. Android支持的Html元素,如下图所示:

这三个字体标签,能够直接使用,称之为“styled text”。内即为黑体字例如:

 
    
  1. <string name="welcome">Welcome to <b>Androidb>!string> 

但是如果将以上的“<”分解,使用Html字符代码的话,用法将有所不同,这两个字符代码:

l “<”对应的字符代码为:<

l “>”对应的字符代码为:>

如下:

 
    
  1. <string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.string> 

称之为“HTML-escaped”text,因为最终文本的显示要为styled text,所以需要将Html-styled text转为 styled text,调用fromHtml()方法。代码如下:

 
    
  1. Resources res = getResources(); 
  2. String text = String.format(res.getString(R.string.welcome_messages), username, mailCount); 
  3. CharSequence styledText = Html.fromHtml(text); 

因为fromHtml()方法转换的对象是html-styled,所以调用此方法之前,必须使用文本格式化(formated text)和TextUtil.htmlEncode()方法,确保所有的可能html字符已经被转码(escape)。如果代码中含有特殊字符“&”“<”等,必须调用以上方法。代码如下:

 
    
  1. String escapedUsername = TextUtil.htmlEncode(username); 
  2.  
  3. Resources res = getResources(); 
  4. String text = String.format(res.getString(R.string.welcome_messages), escapedUsername, mailCount); 
  5. CharSequence styledText = Html.fromHtml(text); 
  6.  

 

测试:如果name中含有html character,不转为html-styled,会有什么情况发生。

xml中字符串format如下:

 
    
  1. <string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.string> 

 

测试代码如下:

 
    
  1. public void onCreate(Bundle savedInstanceState) { 
  2.         super.onCreate(savedInstanceState); 
  3.         setContentView(R.layout.main); 
  4.          
  5.         Resources rs = getResources(); 
  6.         mTextView1 = (TextView) findViewById(R.id.textView1); 
  7.         mTextvView2 = (TextView) findViewById(R.id.textView2); 
  8.          
  9.         String name = new  String(""); 
  10.         int count = 12345
  11.  
  12.         //未转为html-styled 
  13.         format1 = String.format(rs.getString(R.string.welcome_messages), name,count); 
  14.         CharSequence styledText1 = Html.fromHtml(format1); 
  15.         mTextView1.setText(styledText1); 
  16.          
  17.         //转为html-styled 
  18.         format2 = String.format(rs.getString(R.string.welcome_messages), TextUtils.htmlEncode(name),count); 
  19.         CharSequence styledText2 = Html.fromHtml(format2); 
  20.         mTextvView2.setText(styledText2); 
  21.              
  22.     } 

模拟器显示如下:

2. 进入TextUtil类中,htmlEncode()方法做格式化字符代码的转换。且Android中,只接受以上五种特殊字符。代码如下:

 
    
  1. /** 
  2.      * Html-encode the string. 
  3.      * @param s the string to be encoded 
  4.      * @return the encoded string 
  5.      */ 
  6.     public static String htmlEncode(String s) { 
  7.         StringBuilder sb = new StringBuilder(); 
  8.         char c; 
  9.         for (int i = 0; i < s.length(); i++) { 
  10.             c = s.charAt(i); 
  11.             switch (c) { 
  12.             case '<'
  13.                 sb.append("<"); //$NON-NLS-1$ 
  14.                 break
  15.             case '>'
  16.                 sb.append(">"); //$NON-NLS-1$ 
  17.                 break
  18.             case '&'
  19.                 sb.append("&"); //$NON-NLS-1$ 
  20.                 break
  21.             case '\''
  22.                 sb.append("'"); //$NON-NLS-1$ 
  23.                 break
  24.             case '"'
  25.                 sb.append("""); //$NON-NLS-1$ 
  26.                 break
  27.             default
  28.                 sb.append(c); 
  29.             } 
  30.         } 
  31.         return sb.toString(); 
  32.     } 

(三) 源码中

有三处出现htmlEncode()方法。

如下图所示:

第一处:即上文提到的TextUtils类

第二处: TextUtils的测试类,暂时不知道有什么用处

第三处:XmlParser类

定位到代码,如下:

向上查看代码块描述:

显然和之上的分析吻合。这些方法是对xml的输出,输出需要标准化,即 被未来的styled text(或者是其他)准确转换convert。

(四) 流程图

 

 

 

 

(五) 单复数的处理(string format 引入的问题)


文档中说明如下:

测试各个关键字的效果如何。

Xml中定义plurals,如下:

 
    
  1. <plurals name="numberOfSongsAvailable"> 
  2.         <item quantity="zero">Zero song found.item> 
  3.         <item quantity="one">One song found.item> 
  4.         <item quantity="two">Two song found.item> 
  5.         <item quantity="few">Few song found.item> 
  6.         <item quantity="other">Other song found.item> 
  7.         <item quantity="many">Many song found.item> 
  8.     plurals> 

代码中如下:

 
    
  1. public void onCreate(Bundle savedInstanceState) { 
  2.        super.onCreate(savedInstanceState); 
  3.        setContentView(R.layout.main); 
  4.         
  5.        int count1 = 0
  6.        Resources res = getResources(); 
  7.        String songsFound1 = res.getQuantityString(R.plurals.numberOfSongsAvailable, count1, count1); 
  8.        TextView textView1 = (TextView) findViewById(R.id.textView1); 
  9.        textView1.setText(songsFound1); 
  10.         
  11.        int count2 = 1
  12.        String songsFound2 = res.getQuantityString(R.plurals.numberOfSongsAvailable, count2, count2); 
  13.        TextView textView2 = (TextView) findViewById(R.id.textView2); 
  14.        textView2.setText(songsFound2); 
  15.         
  16.        int count3 = 2
  17.        String songsFound3 = res.getQuantityString(R.plurals.numberOfSongsAvailable, count3, count3); 
  18.        TextView textView3 = (TextView) findViewById(R.id.textView3); 
  19.        textView3.setText(songsFound3); 
  20.         
  21.        int count4 = 3
  22.        String songsFound4 = res.getQuantityString(R.plurals.numberOfSongsAvailable, count4, count4); 
  23.        TextView textView4 = (TextView) findViewById(R.id.textView4); 
  24.        textView4.setText(songsFound4); 
  25.         
  26.        int count5 = 4
  27.        String songsFound5 = res.getQuantityString(R.plurals.numberOfSongsAvailable, count5, count5); 
  28.        TextView textView5 = (TextView) findViewById(R.id.textView5); 
  29.        textView5.setText(songsFound5); 
  30.         
  31.        int count6 = 1000
  32.        String songsFound6 = res.getQuantityString(R.plurals.numberOfSongsAvailable, count6, count6); 
  33.        TextView textView6 = (TextView) findViewById(R.id.textView6); 
  34.        textView6.setText(songsFound6); 
  35.         
  36.         
  37.    } 

 

模拟器显示如下:

即在中文状态下,只支持oneother两个关键字。

 

The End!