Android uses custom MultipartEntity to upload files and uses the Volley library to upload files. androidvolley
I recently participated in the CSDN blog star. I hope you can vote for it. Thank you ~ Click here to vote for me ~ Preface
During development, we often need to upload files. The more common is image uploading, such as modifying an Avatar or something. However, this function does not have any default implementation class in Android and iOS. for Android, we can use HttpClient provided by Apache. jar to implement this function. The dependent class is Apache httpmime. the MultipartEntity class in jar. I just want to implement a file upload function, but I still have to download a jar package, which is dozens of KB. This Nima seems to be not human! Today, we will implement the file upload function and understand their principles.
In the previous article, the http post Request Message format analysis and Java implementation file upload, we introduced the http post Message format. If you do not know the POST message format, read this article first.
Custom Implementation of MultipartEntity
We know that the use of network protocols to transmit data is nothing more than a certain protocol. We basically use HTTP when developing mobile applications. HTTP is a set of TCP-based network request protocols. you transmit data in the format specified by this protocol, and then the server returns the data to you. If your protocol parameters are passed incorrectly, the server can only return errors to you.
This is A bit similar to the secret signs between the spies. They have A defined secret number. The two sides met each other. A said: the King of Heaven and the tiger, B: The river demon of the pagoda town. Right, let's talk about things. No, let's get rid of B. The same is true for HTTP. When an HTTP request is sent, the header and parameters are added, and the server parses the parameters. Shape:
POST/api/feed/HTTP/1.1 header data -- delimiter parameter 1 -- delimiter parameter 2
All you need to do is send requests to the server according to the format! Next we will look at the implementation of MultipartEntity:
Public class MultipartEntity implements HttpEntity {private final static char [] MULTIPART_CHARS = "-_ 1234567890 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ". toCharArray ();/*** line break */private final String NEW_LINE_STR = "\ r \ n"; private final String CONTENT_TYPE = "Content-Type :"; private final String CONTENT_DISPOSITION = "Content-Disposition:";/*** text parameters and Character Set */private final String T YPE_TEXT_CHARSET = "text/plain; charset = UTF-8";/*** byte stream parameter */private final String TYPE_OCTET_STREAM = "application/octet-stream "; /*** binary parameter */private final byte [] BINARY_ENCODING = "Content-Transfer-Encoding: binary \ r \ n ". getBytes ();/*** text parameter */private final byte [] BIT_ENCODING = "Content-Transfer-Encoding: 8bit \ r \ n ". getBytes ();/*** separator */private String mBoundary = null;/*** output Stream */ByteArrayOutputStream mOutputStream = new ByteArrayOutputStream (); public MultipartEntity () {this. mBoundary = generateBoundary ();}/*** generate separator ** @ return */private final String generateBoundary () {final StringBuffer buf = new StringBuffer (); final Random rand = new Random (); for (int I = 0; I <30; I ++) {buf. append (MULTIPART_CHARS [rand. nextInt (MULTIPART_CHARS.length)]);} return buf. toS Tring ();}/*** delimiter starting with the parameter ** @ throws IOException */private void writeFirstBoundary () throws IOException {mOutputStream. write ("--" + mBoundary + "\ r \ n "). getBytes ();}/*** add text parameter ** @ param key * @ param value */public void addStringPart (final String paramName, final String value) {writemediutputstream (paramName, value. getBytes (), TYPE_TEXT_CHARSET, BIT_ENCODING, "");}/*** write data to the output stream **@ Param key * @ param rawData * @ param type * @ param encodingBytes * @ param fileName */private void writemediutputstream (String paramName, byte [] rawData, String type, byte [] encodingBytes, string fileName) {try {writeFirstBoundary (); mOutputStream. write (CONTENT_TYPE + type + NEW_LINE_STR ). getBytes (); mOutputStream. write (getContentDispositionBytes (paramName, fileName); mOutputStream. write (encod IngBytes); mOutputStream. write (rawData); mOutputStream. write (NEW_LINE_STR.getBytes ();} catch (final IOException e) {e. printStackTrace () ;}}/*** add binary parameters, such as the byte stream parameter ** @ param key * @ param rawData */public void addBinaryPart (String paramName, final byte [] rawData) {writemediutputstream (paramName, rawData, TYPE_OCTET_STREAM, BINARY_ENCODING, "no-file");}/*** add file parameters, the file upload function can be implemented ** @ para M key * @ param file */public void addFilePart (final String key, final File file) {InputStream fin = null; try {fin = new FileInputStream (file); writeFirstBoundary (); final String type = CONTENT_TYPE + TYPE_OCTET_STREAM + NEW_LINE_STR; mOutputStream. write (getContentDispositionBytes (key, file. getName (); mOutputStream. write (type. getBytes (); mOutputStream. write (BINARY_ENCODING); final byte [] tmp = New byte [4096]; int len = 0; while (len = fin. read (tmp ))! =-1) {mOutputStream. write (tmp, 0, len);} mOutputStream. flush ();} catch (final IOException e) {e. printStackTrace () ;}finally {closeSilently (fin) ;}} private void closeSilently (Closeable closeable) {try {if (closeable! = Null) {closeable. close () ;}} catch (final IOException e) {e. printStackTrace () ;}} private byte [] getContentDispositionBytes (String paramName, String fileName) {StringBuilder stringBuilder = new StringBuilder (); stringBuilder. append (CONTENT_DISPOSITION + "form-data; name = \" "+ paramName +" \ ""); // if (! TextUtils. isEmpty (fileName) {stringBuilder. append ("; filename = \" "+ fileName +" \ "");} return stringBuilder. append (NEW_LINE_STR ). toString (). getBytes () ;}@ Override public long getContentLength () {return mOutputStream. toByteArray (). length ;}@ Override public Header getContentType () {return new BasicHeader ("Content-Type", "multipart/form-data; boundary =" + mBoundary );} @ Override public boolean isChunked () {return false ;}@ Override public boolean isRepeatable () {return false ;}@ Override public boolean isStreaming () {return false ;} @ Override public void writeTo (final OutputStream outstream) throws IOException {// final String endString = "--" + mBoundary + "-- \ r \ n" at the end of the parameter "; // write Terminator mOutputStream. write (endString. getBytes (); // outstream. write (mOutputStream. toByteArray () ;}@ Override public Header getContentEncoding () {return null ;}@ Override public void consumeContent () throws IOException, UnsupportedOperationException {if (isStreaming ()) {throw new UnsupportedOperationException ("Streaming entity does not implement # consumeContent ()") ;}@ Override public InputStream getContent () {return new ByteArrayInputStream (mOutputStream. toByteArray ());}}
You can add parameters through addStringPart, addBinaryPart, and addFilePart to add string parameters, binary parameters, and file parameters respectively. In MultipartEntity, there is a ByteArrayOutputStream object. These parameters are first written to the output stream. When a network request is executed
writeTo(final OutputStream outstream)
The method writes the byte stream data of all parameters to the output stream of the TCP Connection established with the server, so that our parameters are passed to the server. Before that, we need to write data to the ByteArrayOutputStream object in the format.
For example, if I want to send a text, a bitmap image, and a file to the server, this request has three parameters. The Code is as follows:
MultipartEntity multipartEntity = new MultipartEntity (); // The text parameter multipartEntity. addStringPart ("type", "My text Parameters"); Bitmap bmp = BitmapFactory. decodeResource (getResources (), R. drawable. thumb); // binary parameter multipartEntity. addBinaryPart ("images", bitmapToBytes (bmp); // file parameter multipartEntity. addFilePart ("images", new File ("storage/emulated/0/test.jpg"); // POST request HttpPost post = new HttpPost ("url "); // set multipartEntity to post. setEntity (multipartEntity); // use the http client to execute the request HttpClient httpClient = new DefaultHttpClient (); httpClient.exe cute (post );
The output format of MultipartEntity is as follows:
POST/api/feed/HTTP/1.1Content-Type: multipart/form-data; boundary = o3Fhj53z-oKToduAElfBaNU4pZhp4-User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.4.4; M040 Build/KTU84P) Host: www. myhost. comConnection: Keep-AliveAccept-Encoding: gzipContent-Length: 168518 -- o3Fhj53z-oKToduAElfBaNU4pZhp4-Content-Type: text/plain; charset = UTF-8Content-Disposition: form-data; name = "type" Content-Transfer-Encoding: 8 bitThis my type -- o3Fhj53z-oKToduAElfBaNU4pZhp4-Content-Type: application/octet-streamContent-Disposition: form-data; name = "images"; filename = "no-file" Content-Transfer-Encoding: binary here is bitmap's binary data -- o3Fhj53z-oKToduAElfBaNU4pZhp4-Content-Type: application/octet-streamContent-Disposition: form-data; name = "file "; filename = "storage/emulated/0/test.jpg" Content-Transfer-Encoding: binary here is the binary data of the image file-o3Fhj53z-oKToduAElfBaNU4pZhp4 ---
You are familiar with it. This is the POST Message format we mentioned at the beginning of the article. That's right! HttpEntity is responsible for constructing parameters into the HTTP message format. The formats of text parameters, files, and types are fixed. After the construction, the output of the http request is passed through the writeTo (OutputStream) function when the request is executed, and all the parameter data is output to the http output stream.
After understanding these principles, you should understand the code.
Volley implements file upload Volley is a network request library officially launched by Google. This library is simple and excellent, but they do not support adding the file upload function by default. Today, we will define a Request to implement the file upload function. We still need to use the above MultipartEntity class. Let's look at the code below:
/*** MultipartRequest, the returned result is in String format * @ author mrsimple */public class MultipartRequest extends Request <String> {MultipartEntity mMultiPartEntity = new MultipartEntity (); public MultipartRequest (HttpMethod method, String url, Map <String, String> params, RequestListener <String> listener) {super (method, url, params, listener );} /*** @ return */public MultipartEntity getMultiPartEntity () {return mMultiPartEntity;} @ Override public String getBodyContentType () {return mMultiPartEntity. getContentType (). getValue () ;}@ Override public byte [] getBody () {ByteArrayOutputStream bos = new ByteArrayOutputStream (); try {// write the parameters in mMultiPartEntity to mMultiPartEntity in bos. writeTo (bos);} catch (IOException e) {Log. e ("", "IOException writing to ByteArrayOutputStream");} return bos. toByteArray () ;}@ Override protected void deliverResponse (String response) {mListener. onResponse (response) ;}@ 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 ));}}
Sample Code:
MultipartRequest multipartRequest = new MultipartRequest (HttpMethod. POST, "http: // server address", null, new RequestListener <String> () {@ Override public void onStart () {// TODO Auto-generated method stub} @ Override public void onComplete (int stCode, String response, String errMsg) {}}); // obtain the MultipartEntity object MultipartEntity multipartEntity = multipartRequest. getMultiPartEntity (); multipartEntity. addStringPart ("content", "hello"); // Bitmap bitmap = BitmapFactory. decodeResource (getResources (), R. drawable. thumb); // bitmap parameter multipartEntity. addBinaryPart ("images", bitmapToBytes (bitmap); // file parameter multipartEntity. addFilePart ("images", new File ("storage/emulated/0/test.jpg"); // construct Request queue RequestQueue queue = RequestQueue. newRequestQueue (Context); // Add the request to the queue. addRequest (multipartRequest );
Here is what I post to my application: