編輯:關於android開發
使用浏覽器上傳文件,然後通過Wireshark抓包分析,發現發送的數據大概是這個樣子。
MIME Multipart Media Encapsulation, Type: multipart/form-data, Boundary: "----WebKitFormBoundary1UBMMKIkN58civN4" [Type: multipart/form-data] First boundary: ------WebKitFormBoundary1UBMMKIkN58civN4\r\n Encapsulated multipart part: Content-Disposition: form-data; name="name"\r\n\r\n Data (16 bytes) Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n Encapsulated multipart part: (image/png) Content-Disposition: form-data; name="photo[]"; filename="Screenshot (2).png"\r\n Content-Type: image/png\r\n\r\n Portable Network Graphics Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n Encapsulated multipart part: (image/png) Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n Encapsulated multipart part: (image/png) Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n Encapsulated multipart part: (image/png) Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n Encapsulated multipart part: (image/png) Last boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4--\r\n
首先來自定義一個HttpEntity,
package cc.dewdrop.volleydemo.utils; import com.android.volley.VolleyLog; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.message.BasicHeader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.activation.MimetypesFileTypeMap; /** * Created by Tingkuo on 12/1/2015. */ public class FileUploadEntity implements HttpEntity { private static final String TAG = FileUploadEntity.class.getSimpleName(); private static final String BOUNDARY = "__FILE_UPLOAD_ENTITY__"; private ByteArrayOutputStream mOutputStream; public FileUploadEntity() { mOutputStream = new ByteArrayOutputStream(); try { writeFirstBoundary(); } catch (IOException e) { e.printStackTrace(); } } private void writeFirstBoundary() throws IOException { VolleyLog.e("writeFirstBoundary"); mOutputStream.write(("--" + BOUNDARY + "\r\n").getBytes()); mOutputStream.write(("Content-Disposition: form-data; name=\"" + "name" + "\"\r\n\r\n").getBytes()); mOutputStream.write("Content-Transfer-Encoding: binary\n\n".getBytes()); mOutputStream.flush(); } private void writeLastBoundary() throws IOException { VolleyLog.e("writeLastBoundary"); mOutputStream.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes()); } public void addFile(final String key, final File file) { VolleyLog.e("addFile"); InputStream inputStream = null; try { mOutputStream.write(("\r\n--" + BOUNDARY + "\r\n").getBytes()); StringBuilder stringBuilderContentDisposition = new StringBuilder(); stringBuilderContentDisposition.append("Content-Disposition: "); stringBuilderContentDisposition.append("form-data; "); stringBuilderContentDisposition.append("name=\"" + key + "\"; "); stringBuilderContentDisposition.append("filename=\"" + file.getName() + "\"\r\n"); mOutputStream.write(stringBuilderContentDisposition.toString().getBytes()); StringBuilder stringBuilderContentType = new StringBuilder(); stringBuilderContentType.append("Content-Type: "); stringBuilderContentType.append(new MimetypesFileTypeMap().getContentType(file).toString()); stringBuilderContentType.append("\r\n\r\n"); mOutputStream.write(stringBuilderContentType.toString().getBytes()); inputStream = new FileInputStream(file); final byte[] buffer = new byte[1024]; int len = 0; while ((len = inputStream.read(buffer)) != -1) { VolleyLog.e("len --> %s", String.valueOf(len)); mOutputStream.write(buffer, 0, len); } VolleyLog.e("===last====len --> %s", String.valueOf(len)); mOutputStream.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { closeSilently(inputStream); } } private void closeSilently(Closeable closeable) { try { if (closeable != null) { closeable.close(); } } catch (final IOException e) { e.printStackTrace(); } } @Override public boolean isRepeatable() { return false; } @Override public boolean isChunked() { return false; } @Override public long getContentLength() { return mOutputStream.toByteArray().length; } @Override public Header getContentType() { return new BasicHeader("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); } @Override public Header getContentEncoding() { return null; } @Override public InputStream getContent() throws IOException, UnsupportedOperationException { return new ByteArrayInputStream(mOutputStream.toByteArray()); } @Override public void writeTo(OutputStream outputStream) throws IOException { writeLastBoundary(); outputStream.write(mOutputStream.toByteArray()); } @Override public boolean isStreaming() { return false; } @Override public void consumeContent() throws IOException { } }
現在來解釋一下,首先這是支持多文件上傳的,數據格式一共包括四部分,Content-Type,First boundary,文件二進制數據[],及Last boundary。可以有多個文件,使用addFile方法插入,文件之間需要有分隔符Boundary。每個文件需要有Content-Disposition及Content-Type
然後再自定義一個Request,根據需要使用不同的構造方法
package cc.dewdrop.volleydemo.utils; import com.android.volley.AuthFailureError; import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.Response.Listener; import com.android.volley.Response.ErrorListener; import com.android.volley.toolbox.HttpHeaderParser; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Map; /** * Created by Tingkuo on 12/2/2015. */ public class FileUploadRequest extends Request<String> { private final Listener<String> mListener; private FileUploadEntity mFileUploadEntity = new FileUploadEntity(); private Map<String, String> mHeaders = new HashMap<>(); public FileUploadRequest(String url, Listener<String> listener) { this(url, listener, null); } public FileUploadRequest(String url, Listener<String> listener, ErrorListener errorListener) { this(Method.POST, url, listener, errorListener); } public FileUploadRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) { super(method, url, errorListener); this.mListener = listener; } public FileUploadEntity getFileUploadEntity() { return mFileUploadEntity; } @Override public String getBodyContentType() { return mFileUploadEntity.getContentType().getValue(); } public void addHeader(String key, String value) { mHeaders.put(key, value); } @Override public Map<String, String> getHeaders() throws AuthFailureError { return mHeaders; } @Override public byte[] getBody() throws AuthFailureError { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { mFileUploadEntity.writeTo(outputStream); } catch (IOException e) { e.printStackTrace(); } return outputStream.toByteArray(); } @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { String parsed = ""; try { parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); } catch (UnsupportedEncodingException e) { parsed = new String(response.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); } @Override protected void deliverResponse(String response) { if (mListener != null) { mListener.onResponse(response); } } }
代碼是放在Volley中其他類型Request來寫的,沒什麼好說的。
最後就是如何調用
private void simpleUploadFile() { File file = new File(Environment.getExternalStorageDirectory().getPath() + "/upload.png"); fileUploadRequest = new FileUploadRequest( Request.Method.POST, urlList.get(2), new Response.Listener<String>() { @Override public void onResponse(String response) { textViewInfo.setText("Post Succeed:\n" + response.replace("<br>", "\n")); Log.e(TAG, response); dialog.dismiss(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { textViewInfo.setText("Post Failed:\n" + error.getMessage()); Log.e(TAG, error.getMessage()); dialog.dismiss(); } } ); fileUploadRequest.addHeader("User-Agent", "Android 5.1.1"); FileUploadEntity fileUploadEntity = fileUploadRequest.getFileUploadEntity(); fileUploadEntity.addFile("file[]", file); fileUploadEntity.addFile("file[]", file); fileUploadEntity.addFile("file[]", file); fileUploadEntity.addFile("file[]", file); fileUploadEntity.addFile("file[]", file); requestQueue.add(fileUploadRequest); dialog.show(); }
實例化一個新的Request對象,傳入Method,Url,然後通過Request對象來獲取Entity,通過addFile()方法來傳入需要上傳的文件,最後加入requestQueue,使用方法與其他類型Request相同。
備注:
需要添加以下依賴:
compile 'org.apache.httpcomponents:httpcore:4.4.4' compile 'org.apache.httpcomponents:httpmime:4.5.1' compile files('libs/volley.jar') compile files('libs/activation.jar')
UI篇(初識君面),ui初識君面 我們的APP要想吸引用戶,就要把UI(臉蛋)搞漂亮一點。畢竟好的
【java學習系列】 Android第一本書《第一行代碼》,第一行代碼android 開始Java的學習,從Android,開始吧。《第一代碼》開始閱讀和調試demo例
【原】tinker dex文件格式的dump工具tinker-dex-dump,dextinker-dex-dump序言 Tinker是微信推出的熱更新開源項目,同其它熱
Android handler 詳解(面試百分之100問到),androidhandlerhandler在Android中被稱為“消息處理者”,在