之前研究 HTTP Post 的方法時,順手實作了支援 Cookie 等功能,久了之後就會想到如何監控上傳進度的部分,原理都很簡單,但要熟整各個 framework 才能方便進行。所幸網路上好心人士非常多,找到這篇 Android Multipart POST with Progress Bar 真的超佛心的,就順手修改一下一點架構。
實作概念:
繼承 org.apache.http.entity.mime.MultipartEntity 物件後,當寫出資料時,記錄已累積的寫出量,在搭配總共要送出的資料量,簡易的除法就能得知目前所進行的進度了。
我自己的粗略使用:
@ HttpPostMultipartEntity.java:
// 九成九一樣,單純改一些變數名稱
// src: http://toolongdidntread.com/android/android-multipart-post-with-progress-bar/
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
public class HttpPostMultipartEntity extends MultipartEntity {
private final HttpPostProgressHandler handler;
public HttpPostMultipartEntity(final HttpPostProgressHandler handler) {
super();
this.handler = handler;
}
public HttpPostMultipartEntity(final HttpMultipartMode mode, final HttpPostProgressHandler handler) {
super(mode);
this.handler = handler;
}
public HttpPostMultipartEntity(final HttpMultipartMode mode, final String boundary, final Charset charset, final HttpPostProgressHandler handler) {
super(mode,boundary,charset);
this.handler = handler;
}
@Override
public void writeTo(final OutputStream outstream) throws IOException {
super.writeTo(new HttpPostOutputStream(outstream, this.handler));
}
public static class HttpPostOutputStream extends FilterOutputStream {
private final HttpPostProgressHandler handler;
private long transferred;
public HttpPostOutputStream(final OutputStream out, final HttpPostProgressHandler handler) {
super(out);
this.handler = handler;
this.transferred = 0;
}
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
this.transferred += len;
if( this.handler != null )
this.handler.postStatusReport(this.transferred);
}
public void write(int b) throws IOException {
out.write(b);
this.transferred ++;
if( this.handler != null )
this.handler.postStatusReport(this.transferred);
}
}
}
@ HttpPostProgressHandler.java:
public interface HttpPostProgressHandler {
void setPostDataSize(long size);
void postStatusReport(long transferred);
}
HTTP POST Usage:
void doPost( String api_url, String file_path, HttpPostProgressHandler reporter ) {
List<NameValuePair> mParams = new ArrayList<NameValuePair>();
mParams.add( new BasicNameValuePair( "path", remote_path ) );
mParams.add( new BasicNameValuePair( "mode", "upload_file") );
mParams.add( new BasicNameValuePair( "name", filename) );
mParams.add( new BasicNameValuePair( "code", edit_code ) );
// multipart with args
//MultipartEntity entity=new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
HttpPostMultipartEntity entity = new HttpPostMultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, reporter);
for( NameValuePair mItem : mParams )
try {
entity.addPart(item.getName(),new StringBody(mItem.getValue(), Charset.forName("UTF-8")));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
File mFile = new File(file_path);
if( ! mFile.exists() ) {
System.out.println("File not found:"+local_path);
return;
}
// add cookie
CookieStore mCookieStore = BasicCookieStore()
Cookie x = new BasicClientCookie("MyCookie", "MyCookieValue");
((BasicClientCookie)x).setPath("/");
((BasicClientCookie)x).setDomain("ServerDomain");
cookieStore.addCookie( x );
// add file
entity.addPart( "file", new FileBody( mFile ) );
// upload api
HttpPost mHttpPost = new HttpPost(api_url);
mHttpPost.setEntity(entity);
// set post data total size
if( reporter != null )
reporter.setPostDataSize(entity.getContentLength());
// use cookie
HttpClient mHttpClient = new DefaultHttpClient();
HttpContext mHttpContext = new BasicHttpContext();
mHttpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
try {
HttpResponse response = mHttpClient.execute( mHttpPost, mHttpContext );
HttpEntity result = response.getEntity();
System.out.println( "Result:" + EntityUtils.toString(result) );
} catch (Exception e) {
e.printStackTrace();
}
}
Main:
new Thread( new Runnable() {
@Override
public void run() {
doPost(
"http://mytest/api/upload.php" ,
"/mnt/sdcard/test.png",
new HttpPostProgressHandler() {
long total_size = 0;
@Override
public void setPostDataSize(long size) {
total_size = size;
}
@Override
public void postStatusReport(long transferred) {
if(total_size == 0)
return;
System.out.println("Status:"+(float)transferred/total_size);
}
}
);
}
} ).start();
Others:
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
public class HttpQueryUsage {
public static HttpPost createHttpPost(String url, List<NameValuePair> params, List<NameValuePair> files, HttpPostProgressHandler handler) {
if( url == null )
return null;
MultipartEntity entity=new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
if( params != null && params.size() > 0)
for( NameValuePair item : params )
try {
entity.addPart(item.getName(),new StringBody(item.getValue(), Charset.forName("UTF-8")));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if( files != null && files.size() > 0 )
for( NameValuePair file : files ) {
try {
File src = new File(file.getValue());
if(!src.exists())
continue;
entity.addPart( file.getName(), new FileBody( src ) );
} catch (Exception e) {
e.printStackTrace();
}
}
HttpPost post = new HttpPost(url);
post.setEntity(entity);
if(handler!=null)
handler.setPostDataSize(entity.getContentLength());
return post;
}
public static HttpGet createHttpGet(String url, List<NameValuePair> params) {
if( url != null )
return new HttpGet( params == null || params.size() == 0 ? url : url + "?" + URLEncodedUtils.format(params, "utf-8") );
return null;
}
public static HttpResponse executeQuery(HttpUriRequest request, CookieStore cookie_store) throws ClientProtocolException, IOException {
HttpClient mClient = new DefaultHttpClient();
if( cookie_store == null )
return mClient.execute(request);
HttpContext mHttpContext = new BasicHttpContext();
mHttpContext.setAttribute(ClientContext.COOKIE_STORE, cookie_store);
return mClient.execute(request, mHttpContext);
}
public static void exampleGetUsage() {
String url = "http://localhost/login.php";
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add( new BasicNameValuePair("user","username") );
params.add( new BasicNameValuePair("passwd","password") );
try {
CookieStore cookie_store = new BasicCookieStore();
HttpEntity result = HttpQueryUsage.executeQuery(HttpQueryUsage.createHttpGet(url, params), cookie_store).getEntity();
for( Cookie item : cookie_store.getCookies() )
System.out.println("CookieName: "+item.getName()+",CookieValue: "+item.getValue() );
if( result != null )
System.out.println("PageResult:"+EntityUtils.toString(result));
} catch (Exception e) {
e.printStackTrace();
}
}
public static void examplePostUsage() {
String url = "http://localhost/login.php";
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add( new BasicNameValuePair("user","username") );
params.add( new BasicNameValuePair("passwd","password") );
try {
CookieStore cookie_store = new BasicCookieStore();
HttpEntity result = HttpQueryUsage.executeQuery(HttpQueryUsage.createHttpPost(url, params, null, null), cookie_store).getEntity();
for( Cookie item : cookie_store.getCookies() )
System.out.println("CookieName: "+item.getName()+",CookieValue: "+item.getValue() );
if( result != null )
System.out.println("PageResult:"+EntityUtils.toString(result));
} catch (Exception e) {
e.printStackTrace();
}
}
public static void examplePostFileUploadingUsage() {
String url = "http://localhost/login.php";
List<NameValuePair> files = new ArrayList<NameValuePair>();
files.add( new BasicNameValuePair("file1","/mnt/sdcard/test.png") );
try {
CookieStore cookie_store = new BasicCookieStore();
HttpEntity result = HttpQueryUsage.executeQuery(HttpQueryUsage.createHttpPost(url, null, files, null), cookie_store).getEntity();
for( Cookie item : cookie_store.getCookies() )
System.out.println("CookieName: "+item.getName()+",CookieValue: "+item.getValue() );
if( result != null )
System.out.println("PageResult:"+EntityUtils.toString(result));
} catch (Exception e) {
e.printStackTrace();
}
}
}