老古董volley,相比retrofit等新秀來說學(xué)習(xí)曲線平緩,所以項目為了快速上線就選擇了它。有一個需求是通過一個請求上傳多張圖片到服務(wù)器,很快就到gayhub上找到了別人造好的輪子,代碼如下:
/**
* Custom request to make multipart header and upload file.
*
* Sketch Project Studio
* Created by Angga on 27/04/2016 12.05.
*/
public class VolleyMultipartRequest extends Request<NetworkResponse> {
private final String twoHyphens = "--";
private final String lineEnd = "\r\n";
private final String boundary = "apiclient-" + System.currentTimeMillis();
private Response.Listener<NetworkResponse> mListener;
private Response.ErrorListener mErrorListener;
private Map<String, String> mHeaders;
/**
* Default constructor with predefined header and post method.
*
* @param url request destination
* @param headers predefined custom header
* @param listener on success achieved 200 code from request
* @param errorListener on error http or library timeout
*/
public VolleyMultipartRequest(String url, Map<String, String> headers,
Response.Listener<NetworkResponse> listener,
Response.ErrorListener errorListener) {
super(Method.POST, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
this.mHeaders = headers;
}
/**
* Constructor with option method and default header configuration.
*
* @param method method for now accept POST and GET only
* @param url request destination
* @param listener on success event handler
* @param errorListener on error event handler
*/
public VolleyMultipartRequest(int method, String url,
Response.Listener<NetworkResponse> listener,
Response.ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
}
... ...
@Override
protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) {
try {
return Response.success(
response,
HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(NetworkResponse response) {
mListener.onResponse(response);
}
@Override
public void deliverError(VolleyError error) {
mErrorListener.onErrorResponse(error);
}
/**
* Parse string map into data output stream by key and value.
*
* @param dataOutputStream data output stream handle string parsing
* @param params string inputs collection
* @param encoding encode the inputs, default UTF-8
* @throws IOException
*/
private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException {
try {
for (Map.Entry<String, String> entry : params.entrySet()) {
buildTextPart(dataOutputStream, entry.getKey(), entry.getValue());
}
} catch (UnsupportedEncodingException uee) {
throw new RuntimeException("Encoding not supported: " + encoding, uee);
}
}
/**
* Parse data into data output stream.
*
* @param dataOutputStream data output stream handle file attachment
* @param data loop through data
* @throws IOException
*/
private void dataParse(DataOutputStream dataOutputStream, Map<String, DataPart> data) throws IOException {
for (Map.Entry<String, DataPart> entry : data.entrySet()) {
buildDataPart(dataOutputStream, entry.getValue(), entry.getKey());
}
}
/**
* Write string data into header and data output stream.
*
* @param dataOutputStream data output stream handle string parsing
* @param parameterName name of input
* @param parameterValue value of input
* @throws IOException
*/
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
//dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
dataOutputStream.writeBytes(lineEnd);
dataOutputStream.writeBytes(parameterValue + lineEnd);
}
... ...
}
整個類太長只截取一部分,使用中遇到的問題是,當上傳文件的時候同時帶有其他參數(shù)而且參數(shù)中有中文字符串的時候,到了服務(wù)器就是亂碼而英文沒有問題。最初懷疑是accepted這個header設(shè)置的問題,改成utf-8仍然有問題,如果參數(shù)用utf-8先encode一遍則服務(wù)器也要做相應(yīng)的修改,先decode再入庫。因為iOS端沒問題,所以沒有考慮后一個方案。
其他接口使用中文參數(shù)是沒問題的,所以單獨考慮這個上傳request的代碼。在處理函數(shù)的時候,這個類使用的是
dataOutputStream.writeBytes(parameterValue + lineEnd);
直接writeBytes,因為java里邊的字符是雙字節(jié)的,所以如果用這個參數(shù)的話高8位會被丟棄。改為如下語句解決問題:
dataOutputStream.write(parameterValue.getBytes());
dataOutputStream.writeBytes(lineEnd);
gayhub上搜索發(fā)現(xiàn)很多庫直接用了這個文件,可能只是一直使用英文參數(shù)沒有出現(xiàn)問題,相當于埋了一顆雷。如果想要該類的完整代碼,直接搜索VolleyMultipartRequest.java應(yīng)該能搜很多。