請尊重他人的勞動成果,轉載請注明出處:
Android網絡程式設計之使用HttpClient批量上傳檔案(二)AsyncTask+HttpClient并實作上傳進度監聽
運作效果圖:
我曾在《Android網絡程式設計之使用HttpClient批量上傳檔案》一文中介紹過如何通過HttpClient實作多檔案上傳和伺服器的接收。在上一篇主要使用Handler+HttpClient的方式實作檔案上傳。這一篇将介紹使用AsyncTask+HttpClient實作檔案上傳并監聽上傳進度。
監控進度實作:
首先定義監聽器接口。如下所示:
/**
* 進度監聽器接口
*/
public interface ProgressListener {
public void transferred(longtransferedBytes);
}
實作監控進度的關鍵部分就在于記錄已傳輸位元組數,是以我們需重載FilterOutputStream,重寫其中的關鍵方法,實作進度監聽的功能,如下所示,本例中首先重載的是HttpEntityWrapper,顧名思義,就是将需發送的HttpEntity打包,以便計算總位元組數,代碼如下:
package com.jph.ufh.utils;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.http.HttpEntity;
import org.apache.http.entity.HttpEntityWrapper;
/**
* ProgressOutHttpEntity:輸出流(OutputStream)時記錄已發送位元組數
* @author JPH
* Date:2014.11.03
*/
public class ProgressOutHttpEntity extends HttpEntityWrapper {
/**進度監聽對象**/
private final ProgressListener listener;
public ProgressOutHttpEntity(final HttpEntity entity,final ProgressListener listener) {
super(entity);
this.listener = listener;
}
public static class CountingOutputStream extends FilterOutputStream {
private final ProgressListener listener;
private long transferred;
CountingOutputStream(final OutputStream out,
final ProgressListener listener) {
super(out);
this.listener = listener;
this.transferred = 0;
}
@Override
public void write(final byte[] b, final int off, final int len)
throws IOException {
out.write(b, off, len);
this.transferred += len;
this.listener.transferred(this.transferred);
}
@Override
public void write(final int b) throws IOException {
out.write(b);
this.transferred++;
this.listener.transferred(this.transferred);
}
}
@Override
public void writeTo(final OutputStream out) throws IOException {
this.wrappedEntity.writeTo(out instanceof CountingOutputStream ? out
: new CountingOutputStream(out, this.listener));
}
/**
* 進度監聽器接口
*/
public interface ProgressListener {
public void transferred(long transferedBytes);
}
}
最後就是使用上述實作的類和Httpclient進行上傳并顯示進度的功能,非常簡單,代碼如下,使用AsyncTask異步上傳。
/**
* 異步AsyncTask+HttpClient上傳檔案,支援多檔案上傳,并顯示上傳進度
* @author JPH
* Date:2014.10.09
* last modified 2014.11.03
*/
public class UploadUtilsAsync extends AsyncTask<String, Integer, String>{
/**伺服器路徑**/
private String url;
/**上傳的參數**/
private Map<String,String>paramMap;
/**要上傳的檔案**/
private ArrayList<File>files;
private long totalSize;
private Context context;
private ProgressDialog progressDialog;
public UploadUtilsAsync(Context context,String url,Map<String, String>paramMap,ArrayList<File>files) {
this.context=context;
this.url=url;
this.paramMap=paramMap;
this.files=files;
}
@Override
protected void onPreExecute() {//執行前的初始化
// TODO Auto-generated method stub
progressDialog=new ProgressDialog(context);
progressDialog.setTitle("請稍等...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setCancelable(true);
progressDialog.show();
super.onPreExecute();
}
@Override
protected String doInBackground(String... params) {//執行任務
// TODO Auto-generated method stub
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setCharset(Charset.forName(HTTP.UTF_8));//設定請求的編碼格式
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);//設定浏覽器相容模式
int count=0;
for (File file:files) {
// FileBody fileBody = new FileBody(file);//把檔案轉換成流對象FileBody
// builder.addPart("file"+count, fileBody);
builder.addBinaryBody("file"+count, file);
count++;
}
builder.addTextBody("method", paramMap.get("method"));//設定請求參數
builder.addTextBody("fileTypes", paramMap.get("fileTypes"));//設定請求參數
HttpEntity entity = builder.build();// 生成 HTTP POST 實體
totalSize = entity.getContentLength();//擷取上傳檔案的大小
ProgressOutHttpEntity progressHttpEntity = new ProgressOutHttpEntity(
entity, new ProgressListener() {
@Override
public void transferred(long transferedBytes) {
publishProgress((int) (100 * transferedBytes / totalSize));//更新進度
}
});
return uploadFile(url, progressHttpEntity);
}
@Override
protected void onProgressUpdate(Integer... values) {//執行進度
// TODO Auto-generated method stub
Log.i("info", "values:"+values[0]);
progressDialog.setProgress((int)values[0]);//更新進度條
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(String result) {//執行結果
// TODO Auto-generated method stub
Log.i("info", result);
Toast.makeText(context, result, Toast.LENGTH_LONG).show();
progressDialog.dismiss();
super.onPostExecute(result);
}
/**
* 向伺服器上傳檔案
* @param url
* @param entity
* @return
*/
public String uploadFile(String url, ProgressOutHttpEntity entity) {
HttpClient httpClient=new DefaultHttpClient();// 開啟一個用戶端 HTTP 請求
httpClient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5000);// 設定連接配接逾時時間
HttpPost httpPost = new HttpPost(url);//建立 HTTP POST 請求
httpPost.setEntity(entity);
try {
HttpResponse httpResponse = httpClient.execute(httpPost);
if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
return "檔案上傳成功";
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (ConnectTimeoutException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (httpClient != null && httpClient.getConnectionManager() != null) {
httpClient.getConnectionManager().shutdown();
}
}
return "檔案上傳失敗";
}
}
關于伺服器端如何接收:可以參考:《Android網絡程式設計之使用HttpClient批量上傳檔案》,我在裡面已經介紹的很清楚了。
如果你覺得這篇博文對你有幫助的話,請為這篇博文點個贊吧!也可以關注fengyuzhengfan的部落格,收看更多精彩!http://blog.csdn.net/fengyuzhengfan/