Android中URLEncoder空格被轉(zhuǎn)碼為"+"號(hào)的處理辦法
Android前段和后端接口進(jìn)行交互時(shí),經(jīng)常會(huì)遇到特殊字符,比如表情、特殊標(biāo)點(diǎn)等,這樣在Url中是無(wú)法識(shí)別的,需要進(jìn)行轉(zhuǎn)碼,后端進(jìn)行解碼交互。
但當(dāng)使用URLEncoder時(shí),會(huì)發(fā)現(xiàn)字符串中的空格被轉(zhuǎn)換成“+”號(hào),如果編碼后的內(nèi)容入庫(kù)后,將導(dǎo)致讀取時(shí),前段本來(lái)是空格的地方,會(huì)顯示成“+”號(hào)字符。

到底為什么會(huì)這樣,我們還是看看源碼的實(shí)現(xiàn)。
首選,URLEncoder中定義了哪些字符不可以被轉(zhuǎn)碼。
static BitSet dontNeedEncoding;
dontNeedEncoding中就包含了不允許轉(zhuǎn)碼的字符集合,只有在這里面能找不到的字符才會(huì)被正常轉(zhuǎn)碼。下面是dontNeedEncoding初始化過(guò)程
static {
//創(chuàng)建一個(gè)容量為256的位集合
dontNeedEncoding = new BitSet(256);
int i;
//循環(huán)a-z,將其字符值(不是字符串值)存入
for (i = 'a'; i <= 'z'; i++) {
dontNeedEncoding.set(i);
}
//同上
for (i = 'A'; i <= 'Z'; i++) {
dontNeedEncoding.set(i);
}
//同上
for (i = '0'; i <= '9'; i++) {
dontNeedEncoding.set(i);
}
//在這個(gè)地方,官方特意做了說(shuō)明
//空格將被編碼為加號(hào)
dontNeedEncoding.set(' '); /* encoding a space to a + is done
* in the encode() method */
dontNeedEncoding.set('-');
dontNeedEncoding.set('_');
dontNeedEncoding.set('.');
dontNeedEncoding.set('*');
//默認(rèn)編碼格式
dfltEncName = AccessController.doPrivileged(
new GetPropertyAction("file.encoding")
);
}上面的代碼我們看到,除了英文字母,數(shù)字和幾個(gè)能識(shí)別的字符外,都需要轉(zhuǎn)碼。
我們?cè)賮?lái)看看encode方法。
public static String encode(String s, String enc)
throws UnsupportedEncodingException {
//標(biāo)記是否有字符被轉(zhuǎn)碼了,如果沒(méi)有,就直接返回原始字符串
//如果有,就返回out的結(jié)果
boolean needToChange = false;
//存放轉(zhuǎn)碼后的結(jié)果
StringBuffer out = new StringBuffer(s.length());
Charset charset;
CharArrayWriter charArrayWriter = new CharArrayWriter();
//如果未指定編碼,拋出異常
if (enc == null)
throw new NullPointerException("charsetName");
try {
charset = Charset.forName(enc);
} catch (IllegalCharsetNameException e) {
throw new UnsupportedEncodingException(enc);
} catch (UnsupportedCharsetException e) {
throw new UnsupportedEncodingException(enc);
}
//遍歷要編碼的字符串
for (int i = 0; i < s.length();) {
//取出指定位置的字符
int c = (int) s.charAt(i);
if (dontNeedEncoding.get(c)) {
//這里,判斷如果字符是空格,就轉(zhuǎn)為“+”
if (c == ' ') {
c = '+';
needToChange = true;
}
out.append((char)c);
i++;
} else {
// convert to external encoding before hex conversion
do {
charArrayWriter.write(c);
/*
* 下面就是轉(zhuǎn)碼unicode相關(guān)代碼
*/
if (c >= 0xD800 && c <= 0xDBFF) {
......
}
i++;
} while (i < s.length() && !dontNeedEncoding.get((c = (int) s.charAt(i))));
charArrayWriter.flush();
String str = new String(charArrayWriter.toCharArray());
byte[] ba = str.getBytes(charset);
for (int j = 0; j < ba.length; j++) {
//添加百分號(hào),比如a'a轉(zhuǎn)為a%27a
out.append('%');
......
}
charArrayWriter.reset();
needToChange = true;
}
}
return (needToChange? out.toString() : s);
}我們討論的問(wèn)題,就是下面這幾行。

那么如何處理該問(wèn)題呢?
注意:網(wǎng)上那種替換空格或加號(hào)的方法是不可行的,因?yàn)榭赡軙?huì)替換掉正常的空格和加號(hào)。
建議自己仿照官方的代碼,寫(xiě)一套自己轉(zhuǎn)碼和解碼過(guò)程,這個(gè)不難的?;蛘哒业谌降模ū热鐂pring提供的 UriUtils )。
另外,Android提供了Uri.encode,雖然可以正常轉(zhuǎn)碼空格,但是它不需要轉(zhuǎn)換的字符和URLEncode有一點(diǎn)差別,大家在用的時(shí)候,根據(jù)情況選擇即可。
下面是Uri.encode中不會(huì)被轉(zhuǎn)碼的字符
/**
* Returns true if the given character is allowed.
*
* @param c character to check
* @param allow characters to allow
* @return true if the character is allowed or false if it should be
* encoded
*/
private static boolean isAllowed(char c, String allow) {
return (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c >= '0' && c <= '9')
|| "_-!.~'()*".indexOf(c) != NOT_FOUND
|| (allow != null && allow.indexOf(c) != NOT_FOUND);
}總結(jié)
到此這篇關(guān)于Android中URLEncoder空格被轉(zhuǎn)碼為"+"號(hào)的處理辦法的文章就介紹到這了,更多相關(guān)Android URLEncoder空格被轉(zhuǎn)碼+號(hào)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android實(shí)現(xiàn)隱藏狀態(tài)欄和標(biāo)題欄
這篇文章主要介紹了Android實(shí)現(xiàn)隱藏狀態(tài)欄和標(biāo)題欄的相關(guān)資料,需要的朋友可以參考下2015-06-06
android ListView結(jié)合x(chóng)utils3仿微信實(shí)現(xiàn)下拉加載更多
本篇文章主要介紹了android ListView結(jié)合x(chóng)utils3仿微信實(shí)現(xiàn)下拉加載更多,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11
史上最全Android build.gradle配置詳解(小結(jié))
這篇文章主要介紹了史上最全Android build.gradle配置詳解(小結(jié)),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-04-04
Android入門(mén)教程之RecyclerView的具體使用詳解
RecyclerView是Android一個(gè)更強(qiáng)大的控件,其不僅可以實(shí)現(xiàn)和ListView同樣的效果,還有優(yōu)化了ListView中的各種不足。其可以實(shí)現(xiàn)數(shù)據(jù)縱向滾動(dòng),也可以實(shí)現(xiàn)橫向滾動(dòng)(ListView做不到橫向滾動(dòng))。接下來(lái)講解RecyclerView的用法2021-10-10
Android自定View實(shí)現(xiàn)滑動(dòng)驗(yàn)證效果的代碼
這篇文章主要介紹了Android自定View實(shí)現(xiàn)滑動(dòng)驗(yàn)證效果,代碼分為自定義屬性代碼和自定義view代碼及使用方法,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-12-12
Android使用RecyclerView實(shí)現(xiàn)列表數(shù)據(jù)選擇操作
這篇文章主要為大家詳細(xì)介紹了Android使用RecyclerView結(jié)合CheckBox實(shí)現(xiàn)列表數(shù)據(jù)選擇操作,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
Android 手機(jī)防止休眠的兩種實(shí)現(xiàn)方法
這篇文章主要介紹了Android 手機(jī)防止休眠方法的相關(guān)資料,一種是在Manifest.xml文件里面聲明,另外一種方法是在代碼里面修改LayoutParams的標(biāo)志位,需要的朋友可以參考下2017-08-08
Android?RecyclerBarChart繪制使用教程
這篇文章主要為大家介紹了Android?RecyclerBarChart繪制使用教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12

