在Gooogle I/O 2013年的大會上面,展現的Volley庫,已經成爲android開發中最經常使用的處理和緩存網絡請求的庫。
若是你尚未看過Gooogle I/O中關於Volley的介紹(https://developers.google.com/events/io/sessions/325304728),在繼續這篇文章以前我建議你先去看看關於Volley的介紹,對它有一些基本的理解。java
中文的話能夠看下這篇翻譯的文章。android
連接描述json
關於Volley的使用網上有不少的教程,這裏主要講一下如何使用Volley上傳圖片的問題。api
這裏上傳的圖片是頭像,因此圖片的大小已經固定好了。數組
咱們有兩種方式能夠完成上傳圖片到服務器:瀏覽器
使用Multipart Request緩存
發送圖片的字符串到服務器服務器
咱們使用Volley均可以實現。網絡
使用Multipart Request的方式session
Multipart Request是一種HTTP請求,能夠經過HTTP客戶端或者瀏覽器發送文件和數據到HTTP服務器,Volley 支持這種類型。
主要思路:
將須要上傳的圖片轉換爲MultipartRequest請求內容須要的數組格式,經過MultipartRequest上傳到服務器,在服務器端解析。
首先將咱們須要上傳的圖片轉換爲數組數據。
//將圖片轉換爲數組
publicbyte[]getImageBytes(Bitmap bmp){ if(bmp==null)returnnull; ByteArrayOutputStream baos =newByteArrayOutputStream(); bmp.compress(Bitmap.CompressFormat.JPEG,100,baos); byte[] imageBytes = baos.toByteArray(); returnimageBytes; }
調用MultipartRequest請求
//設置請求的內容類型
privatefinalString boundary ="apiclient-"+ System.currentTimeMillis(); privatefinalString mimeType ="multipart/form-data;boundary="+ boundary;
//保存內容的數組集合
privatebyte[] multipartBody;
//須要上傳的圖片
privateBitmap bitmap;
//經過MultipartRequest上傳圖片的方法
privatevoiduploadAvatarByMultipart(){
//根據圖片的路徑,將其轉換爲bitmap類型
File file =newFile(ImageUtils.getAvatarPath(activity,"user_avatar"), username +".jpg"); String path = file.getAbsolutePath(); bitmap = BitmapFactory.decodeFile(path);
//調用圖片轉數組的方法,得到圖片的數組數據
multipartBody =getImageBytes(bitmap);
//上傳圖片到服務器的請求地址
String url=Application.SERVER_ROOT+"?"+I.KEY_REQUEST+"="+I.REQUEST_UPLOAD_AVATAR;
//執行MultipartRequest請求,設置上傳的內容和內容類型,executeRequest會將請求添加到請求隊列中。
executeRequest(newMultipartRequest(url,MessageBean.class,null,uploadAvatarByMultipartListener(),errorListener(),mimeType, multipartBody)); }
自定義回調函數,能夠添加對服務器請求結果的處理
privateResponse.ListeneruploadAvatarByMultipartListener() { returnnewResponse.Listener() { @Override publicvoidonResponse(MessageBean messageBean) { Utils.showToast(mContext,"upload avatar success!!!",Toast.LENGTH_SHORT); } }; }
自定義MultipartRequest,須要繼承Request,而且重寫getBodyContentType方法和getBody方法,分別返回傳過來的內容和內容類型。
publicclassMultipartRequestextendsRequest { privatefinalGson mGson =newGson(); privatefinalClass mClazz; privatefinalListener mListener; privatefinalMap mHeaders; privatefinalString mMimeType; privatefinalbyte[] mMultipartBody; publicMultipartRequest(String url, Class clazz, Map headers, Listener listener, ErrorListener errorListener, String mimeType,byte[] multipartBody) { this(Method.POST, url, clazz, headers,mimeType, multipartBody, listener, errorListener); } publicMultipartRequest(intmethod, String url, Class clazz, Map headers, String mimeType,byte[] multipartBody, Listener listener, ErrorListener errorListener) { super(method, url, errorListener); this.mClazz= clazz; this.mHeaders= headers; this.mListener= listener; this.mMimeType= mimeType; this.mMultipartBody= multipartBody; } @Override publicMapgetHeaders()throwsAuthFailureError { return(mHeaders !=null) ? mHeaders :super.getHeaders(); } @Override publicStringgetBodyContentType() { returnmMimeType; } @Override publicbyte[]getBody()throwsAuthFailureError { returnmMultipartBody; } @Override protectedResponseparseNetworkResponse(NetworkResponse response) { try{ String json =newString(response.data, HttpHeaderParser.parseCharset(response.headers)); returnResponse.success(mGson.fromJson(json, mClazz), HttpHeaderParser.parseCacheHeaders(response)); }catch(Exception e) { returnResponse.error(newParseError(e)); } } @Override protectedvoiddeliverResponse(T response) { mListener.onResponse(response); } }
服務器端解析數據並處理
privatevoiduploadAvatar(HttpServletRequest request, HttpServletResponse response)throwsIOException { String userName=request.getParameter("userName"); String path=I.AVATAR_PATH; String fileName=userName+".jpg"; System.out.println("頭像上傳路徑:"+ path + fileName); File file =newFile(path,fileName); FileOutputStream fos =newFileOutputStream(file); byte[] buffer =newbyte[1024*8]; intlen; while((len = request.getInputStream().read(buffer)) != -1) { fos.write(buffer,0, len); } booleanisSuccess =false; UserBean user = biz.findUserByUserName(userName); user.setAvatar(typeAvatar+"/"+ fileName); isSuccess = biz.updateUser(user); ObjectMapper om=newObjectMapper(); if(isSuccess){ om.writeValue(response.getOutputStream(),"上傳頭像成功"); }else{ om.writeValue(response.getOutputStream(),"上傳頭像失敗"); } fos.close(); }
使用發送圖片字符串的方式
咱們這裏使用的圖片字符串爲Base64編碼的字符串。
Base64是網絡上最多見的用於傳輸8Bit字節代碼的編碼方式之一,你們能夠查看RFC2045~RFC2049,上面有MIME的詳細規範。Base64編碼可用於在HTTP環境下傳遞較長的標識信息。例如,在Java Persistence系統Hibernate中,就採用了Base64來將一個較長的惟一標識符(通常爲128-bit的UUID)編碼爲一個字符串,用做HTTP表單和HTTP GET URL中的參數。在其餘應用程序中,也經常須要把二進制數據編碼爲適合放在URL(包括隱藏表單域)中的形式。此時,採用Base64編碼具備不可讀性,即所編碼的數據不會被人用肉眼所直接看到。
主要思路:
將須要上傳的圖片轉換爲Base64編碼的字符串,經過Volley的StringRequest請求發生給服務器,並在服務器端解碼。
根據圖片存儲的地址,將其轉化爲Base64編碼字符串
//圖片轉化成base64字符串
publicstaticStringgetImageStr(String filePath) {
//將圖片文件轉化爲字節數組字符串,並對其進行Base64編碼處理
InputStream in =null; byte[] data =null;
//讀取圖片字節數組
try{ in =newFileInputStream(filePath); data =newbyte[in.available()]; in.read(data); in.close(); }catch(IOException e) { e.printStackTrace(); }
//對字節數組Base64編碼
//返回Base64編碼過的字節數組字符串
returnBase64.encodeToString(data,Base64.DEFAULT); }
使用Volley的StringRequest請求,並重寫getParams方法,將圖片的字符串以參數的形式傳遞。
privatevoiduploadAvatar(){
//此處添加progress dialog
//設置服務器請求地址
String url=Application.SERVER_ROOT+"?"+I.KEY_REQUEST+"="+I.REQUEST_UPLOAD_AVATAR;
//執行StringRequest請求,請求類型爲post,自定義uploadResponseListener回調函數,添加父類中公共的errorListener方法
executeRequest(newStringRequest(Request.Method.POST,url,uploadResponseListener(),errorListener()){ @Override protectedMapgetParams()throwsAuthFailureError {
//獲取圖片文件
File file =newFile(ImageUtils.getAvatarPath(activity,"user_avatar"), username +".jpg");
//獲取圖片存放地址的絕對路徑
String path = file.getAbsolutePath();
//將圖片轉換爲字符串
String image =GetImageStr(path);
//建立參數集合
Map params =newHashtable();
//將圖片字符串添加到參數集合中
params.put("image", image); params.put("userName", username);
//返回參數集合
returnparams; } }); }
自定義回調函數,能夠添加對服務器請求結果的處理
privateResponse.ListeneruploadResponseListener() { returnnewResponse.Listener() { @Override publicvoidonResponse(String s) { Utils.showToast(mContext,"upload avatar success!",Toast.LENGTH_SHORT); } }; }
服務器端解析數據並處理
privatevoiduploadAvatar(HttpServletRequest request, HttpServletResponse response)throwsIOException { String userName=request.getParameter("userName"); String image = request.getParameter("image"); String path=I.AVATAR_PATH; String fileName=userName+".jpg"; System.out.println("頭像上傳路徑:"+ path + fileName); File file =newFile(path,fileName); FileOutputStream fos =newFileOutputStream(file); BASE64Decoder decoder =newBASE64Decoder(); try{ //Base64解碼 byte[] b = decoder.decodeBuffer(image); fos.write(b); fos.flush(); fos.close(); }catch(Exception e) { System.out.print(e); } booleanisSuccess =false; UserBean user = biz.findUserByUserName(userName); user.setAvatar(typeAvatar+"/"+ fileName); isSuccess = biz.updateUser(user); ObjectMapper om=newObjectMapper(); if(isSuccess){ om.writeValue(response.getOutputStream(),"上傳頭像成功"); }else{ om.writeValue(response.getOutputStream(),"上傳頭像失敗"); } }
好啦,以上就是使用Volley上傳圖片的兩種方法,但願能幫助到你們。
參考:
Android Volley Tutorial to Upload Image to Server(Android Volley Tutorial to Upload Image to Server) Working POST Multipart Request with Volley and without HttpEntity(java - Working POST Multipart Request with Volley and without HttpEntity - Stack Overflow)