Android使用Volley框架定制PostUploadRequest上傳文件
發(fā)現(xiàn)問(wèn)題
項(xiàng)目中有發(fā)表動(dòng)態(tài)的功能,該功能可以將文本和圖片上傳至服務(wù)器。
Volley通過(guò)定制PostUploadRequest實(shí)現(xiàn)文件上傳的功能,本文以一張圖片上傳為例。
數(shù)據(jù)格式
以下為項(xiàng)目中圖片上傳實(shí)例的數(shù)據(jù)格式
多張圖片上傳可通過(guò)添加——WebKitFormBoundary 內(nèi)容實(shí)現(xiàn)
POST /CloudLife/user/social HTTP/1.1 Host: localhost Connection: keep-alive Cache-Control: max-age=0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Origin: http://localhost User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryzayymBT8Owg2UzBR Referer: http://localhost/CloudLife/upload.jsp Accept-Encoding: gzip,deflate,sdch Accept-Language: zh-CN,zh;q=0.8 Cookie: CLOUD_LIFE=03F21B9A9D9B4FF2BF443290A9CD8E2C; USER=18060506304; JSESSIONID=C4AB532929FA43230FA193A98197F962 Content-Length: 12444 ------WebKitFormBoundaryzayymBT8Owg2UzBR Content-Disposition: form-data; name="text" 發(fā)表的圈子內(nèi)容 ------WebKitFormBoundaryzayymBT8Owg2UzBR Content-Disposition: form-data; name="file"; filename="這里是文件名" Content-Type: image/png 這里空一行 接下來(lái)是二進(jìn)制圖片文件內(nèi)容 ------WebKitFormBoundaryzayymBT8Owg2UzBR-- 這里為空白的一行
總共有加上結(jié)尾行,有五行,圖片的二進(jìn)制數(shù),整個(gè)算一行;下面來(lái)分析下:
1、第一行:”–” + boundary + “\r\n” ;
文件上傳在提交數(shù)據(jù)的開(kāi)始標(biāo)志不變;
2、第二行:Content-Disposition: form-data; name=”參數(shù)的名稱”; filename=”上傳的文件名” + “\r\n”
3、第三行:Content-Type: 文件的 mime 類型 + “\r\n”
這一行是文件上傳必須要的,而普通的文字提交可有可無(wú),mime 類型需要根據(jù)文檔查詢;
4、第四行:”\r\n”
5、第五行文件的二進(jìn)制數(shù)據(jù) + “\r\n”:
結(jié)尾行:”–” + boundary + “–” + “\r\n”
可以同時(shí)上傳多個(gè)文件,上傳多個(gè)文件的時(shí)候重復(fù)1、2、3、4、5步,在最后的一個(gè)文件的末尾加上統(tǒng)一的結(jié)束行。
上傳的圖像實(shí)體類
import java.io.ByteArrayOutputStream;
import android.graphics.Bitmap;
/*
* 上傳的圖像實(shí)體類
* */
public class FormImage {
// 參數(shù)的名稱
private String mName;
// 文件名
private String mFileName;
// 文件的 mime,需要根據(jù)文檔查詢
private String mMime;
// 需要上傳的圖片資源,因?yàn)檫@里測(cè)試為了方便起見(jiàn),直接把 bitmap 傳進(jìn)來(lái),真正在項(xiàng)目中一般不會(huì)這般做,
// 而是把圖片的路徑傳過(guò)來(lái),在這里對(duì)圖片進(jìn)行二進(jìn)制轉(zhuǎn)換
private Bitmap mBitmap = null;
public FormImage(Bitmap bitmap) {
this.mBitmap = bitmap;
}
public String getName() {
return "file";
}
public String getFileName() {
return "add.png";
}
// 對(duì)圖片進(jìn)行二進(jìn)制轉(zhuǎn)換
public byte[] getValue() {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
mBitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
return bos.toByteArray();
}
// 因?yàn)槲抑朗?png 文件,所以直接根據(jù)文檔查的
public String getMime() {
return "image/png";
}
}
定制PostUploadRequest
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.protocol.HTTP;
import org.json.JSONException;
import org.json.JSONObject;
import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import android.util.Log;
/*
* 發(fā)送文件的volley
* post請(qǐng)求 Cookie
* */
public class PostUploadRequest extends Request<JSONObject> {
private Map<String, String> sendHeader = new HashMap<String, String>();
// 正確數(shù)據(jù)的時(shí)候回掉用
private Response.Listener<JSONObject> mListener;
// 請(qǐng)求 數(shù)據(jù)通過(guò)參數(shù)的形式傳入
private String content;
private FormImage mImage;
// 數(shù)據(jù)分隔線
private String BOUNDARY = "----CloudLifeUpLoadImage";
private String MULTIPART_FORM_DATA = "multipart/form-data";
public PostUploadRequest(String url, String text, FormImage Item, Response.Listener<JSONObject> listener,Response.ErrorListener errorListener) {
super(Method.POST, url, errorListener);
this.mListener = listener;
setShouldCache(false);
mImage = Item;
content = text;
// 設(shè)置請(qǐng)求的響應(yīng)事件,因?yàn)槲募蟼餍枰^長(zhǎng)的時(shí)間,所以在這里加大了,設(shè)為5秒
setRetryPolicy(new DefaultRetryPolicy(5000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
}
/*
* 這里開(kāi)始解析數(shù)據(jù)
* @param response
* Response from the network
* @return
* */
@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
// 防止中文亂碼
@SuppressWarnings("deprecation")
String jsonString = new String(response.data, HTTP.UTF_8);
JSONObject jsonObject = new JSONObject(jsonString);
Log.w("upLoad", "jsonObject " + jsonObject.toString());
return Response.success(jsonObject, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
/*
* 回調(diào)正確的數(shù)據(jù)
* @param response
* The parsed response returned by
* */
@Override
protected void deliverResponse(JSONObject response) {
mListener.onResponse(response);
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
return sendHeader;
}
public void setSendCookie(String cookie) {
sendHeader.put("Cookie", cookie);
}
@Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
StringBuffer sb = new StringBuffer();
if (content == null) {
/**
* 圖片
*/
/* 第一行 */
// `"--" + BOUNDARY + "\r\n"`
sb.append("--" + BOUNDARY + "\r\n");
/* 第二行 */
// Content-Disposition: form-data; name="參數(shù)的名稱"; filename="上傳的文件名" +
// "\r\n"
sb.append("Content-Disposition: form-data;");
sb.append(" name=\"");
sb.append(mImage.getName());
sb.append("\"");
sb.append("; filename=\"");
sb.append(mImage.getFileName());
sb.append("\"");
sb.append("\r\n");
/* 第三行 */
// Content-Type: 文件的 mime 類型 + "\r\n"
sb.append("Content-Type: ");
sb.append(mImage.getMime());
sb.append("\r\n");
/* 第四行 */
// "\r\n" 空白的一行
sb.append("\r\n");
try {
bos.write(sb.toString().getBytes("utf-8"));
/* 第五行 */
// 文件的二進(jìn)制數(shù)據(jù) + "\r\n"
bos.write(mImage.getValue());
bos.write("\r\n".getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
/* 結(jié)尾行 */
// `"--" + BOUNDARY + "--" + "\r\n"`
String endLine = "--" + BOUNDARY + "--" + "\r\n";
try {
bos.write(endLine.toString().getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
Log.v("upLoad", "=====formImage====\n" + bos.toString());
return bos.toByteArray();
}
/**
* 文字
*/
/* 第一行 */
// `"--" + BOUNDARY + "\r\n"`
sb.append("--" + BOUNDARY + "\r\n");
/* 第二行 */
// Content-Disposition: form-data; name="text" + "\r\n"
sb.append("Content-Disposition: form-data;");
sb.append(" name=\"");
sb.append("text");
sb.append("\"");
sb.append("\r\n");
/* 第三行 */
// "\r\n" 空白的一行
sb.append("\r\n");
/* 第四行 */
// 文本內(nèi)容
sb.append(content);
sb.append("\r\n");
if (mImage == null) {
/* 結(jié)尾行 */
// `"--" + BOUNDARY + "--" + "\r\n"`
String endLine = "--" + BOUNDARY + "--" + "\r\n";
try {
bos.write(sb.toString().getBytes("utf-8"));
bos.write(endLine.toString().getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
Log.v("upLoad", "=====formImage====\n" + bos.toString());
return bos.toByteArray();
} else {
/**
* 圖片
*/
/* 第一行 */
// `"--" + BOUNDARY + "\r\n"`
sb.append("--" + BOUNDARY + "\r\n");
/* 第二行 */
// Content-Disposition: form-data; name="參數(shù)的名稱"; filename="上傳的文件名" +
// "\r\n"
sb.append("Content-Disposition: form-data;");
sb.append(" name=\"");
sb.append(mImage.getName());
sb.append("\"");
sb.append("; filename=\"");
sb.append(mImage.getFileName());
sb.append("\"");
sb.append("\r\n");
/* 第三行 */
// Content-Type: 文件的 mime 類型 + "\r\n"
sb.append("Content-Type: ");
sb.append(mImage.getMime());
sb.append("\r\n");
/* 第四行 */
// "\r\n" 空白的一行
sb.append("\r\n");
try {
bos.write(sb.toString().getBytes("utf-8"));
/* 第五行 */
// 文件的二進(jìn)制數(shù)據(jù) + "\r\n"
bos.write(mImage.getValue());
bos.write("\r\n".getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
/* 結(jié)尾行 */
// `"--" + BOUNDARY + "--" + "\r\n"`
String endLine = "--" + BOUNDARY + "--" + "\r\n";
try {
bos.write(endLine.toString().getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
Log.v("upLoad", "=====formImage====\n" + bos.toString());
return bos.toByteArray();
}
// Content-Type: multipart/form-data; boundary=----------8888888888888
@Override
public String getBodyContentType() {
return MULTIPART_FORM_DATA + "; boundary=" + BOUNDARY;
}
}
實(shí)例
RequestQueue mQueue = SingleRequestQueue.getRequestQueue();
FormImage image;
if (imageUri != null) {
Bitmap bitmap = null;
try {// 將路徑轉(zhuǎn)化成bitmap
bitmap=BitmapFactory.decodeStream(
getContentResolver().openInputStream(imageUri));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
image = new FormImage(bitmap);
} else
image = null;
PostUploadRequest post = new PostUploadRequest(C.api.userIcon, null, image,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
try {
//TODO
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("VolleyError", error.getMessage(), error);
}
});
if (!customer.getCookie().equals("")) {
// 向服務(wù)器發(fā)起post請(qǐng)求時(shí)加上cookie字段
post.setSendCookie(customer.getCookie());
}
mQueue.add(post);
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android框架Volley之利用Imageloader和NetWorkImageView加載圖片的方法
- Android框架Volley使用之Post請(qǐng)求實(shí)現(xiàn)方法
- Android框架Volley使用之Json請(qǐng)求實(shí)現(xiàn)
- Android框架Volley使用:ImageRequest請(qǐng)求實(shí)現(xiàn)圖片加載
- Android中volley封裝實(shí)踐記錄(二)
- Android中volley封裝實(shí)踐記錄
- Android Volley擴(kuò)展實(shí)現(xiàn)支持進(jìn)度條的文件上傳功能
- Android使用Volley實(shí)現(xiàn)上傳文件功能
- 解析Android框架之Volley源碼
相關(guān)文章
Android 利用ViewPager實(shí)現(xiàn)圖片可以左右循環(huán)滑動(dòng)效果附代碼下載
本文通過(guò)一個(gè)小demo給大家展示一段代碼實(shí)現(xiàn)viewpage圖片左右循環(huán)滑動(dòng)效果,對(duì)viewgager循環(huán)滑動(dòng)相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2015-11-11
android通過(guò)servlet上傳文件到服務(wù)器
這篇文章主要為大家詳細(xì)介紹了android通過(guò)servlet上傳文件到服務(wù)器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06
Android 仿摩拜單車共享單車進(jìn)度條實(shí)現(xiàn)StepView效果
這篇文章主要介紹了android 仿摩拜單車共享單車進(jìn)度條實(shí)現(xiàn)StepView效果的實(shí)例,通過(guò)定義五個(gè)狀態(tài),分別為:為完成、正在進(jìn)行、已完成、終點(diǎn)完成、終點(diǎn)未完成。具體實(shí)現(xiàn)代碼,大家參考下2017-03-03
Android實(shí)現(xiàn)簡(jiǎn)易計(jì)算器(可以實(shí)現(xiàn)連續(xù)計(jì)算)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)易計(jì)算器,可以實(shí)現(xiàn)連續(xù)計(jì)算,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03
Android TV listview及焦點(diǎn)處理
這篇文章主要介紹了Android TV listview及焦點(diǎn)處理的相關(guān)資料,需要的朋友可以參考下2017-06-06
Android開(kāi)發(fā)實(shí)現(xiàn)消除屏幕鎖的方法
這篇文章主要介紹了Android開(kāi)發(fā)實(shí)現(xiàn)消除屏幕鎖的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android鎖屏的原理及消除屏幕鎖的相關(guān)操作技巧,需要的朋友可以參考下2017-09-09
Android實(shí)現(xiàn)圓形ProgressBar停止轉(zhuǎn)動(dòng)的方法詳解
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)圓形ProgressBar停止轉(zhuǎn)動(dòng)方法的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03
Android?ViewPager實(shí)現(xiàn)左右滑動(dòng)翻頁(yè)效果
這篇文章主要為大家詳細(xì)介紹了Android?ViewPager實(shí)現(xiàn)左右滑動(dòng)翻頁(yè)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12

