使用进度条通过MultipartEntityBuilder通过HTTP表单上传文件

简短版本org.apache...MultipartEntity已被弃用,其升级MultipartEntityBuilder在我们的在线论坛中显示不足。 我们来解决这个问题。 如何注册一个callback,所以我的(Android)应用程序可以显示进度条上传文件?

长版本 – 这里是MultipartEntityBuilder的“缺less污垢简单的例子”:

 public static void postFile(String fileName) throws Exception { // Based on: https://stackoverflow.com/questions/2017414/post-multipart-request-with-android-sdk HttpClient client = new DefaultHttpClient(); HttpPost post = new HttpPost(SERVER + "uploadFile"); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); builder.addPart("file", new FileBody(new File(fileName))); builder.addTextBody("userName", userName); builder.addTextBody("password", password); builder.addTextBody("macAddress", macAddress); post.setEntity(builder.build()); HttpResponse response = client.execute(post); HttpEntity entity = response.getEntity(); // response.getStatusLine(); // CONSIDER Detect server complaints entity.consumeContent(); client.getConnectionManager().shutdown(); } // FIXME Hook up a progress bar! 

我们需要修复那个FIXME 。 (一个额外的好处是可以中断的上传。)但是(请纠正我是否我错了),所有在线的例子似乎不足。

例如,这个http://pastebin.com/M0uNZ6SB上传文件为“binary / octet-stream”。 不是“多部分/forms数据”。 我需要真正的领域。

这个例子, file upload与Java(带进度条) ,显示如何覆盖*Entity*Stream 。 所以,也许我可以告诉MultipartEntityBuilder .create()一个重载的实体来.create()它的上传进度?

所以,如果我想重写一些东西,并用每1000个字节发送一个信号的计数stream代替内置stream,那么也许我可以扩展FileBody部分,并覆盖它的getInputStream和/或writeTo

但是当我尝试class ProgressiveFileBody extends FileBody {...} ,我得到臭名昭着的java.lang.NoClassDefFoundError

所以,当我围绕我的.jar文件进行search时,寻找缺失的Def,是否有人可以检查我的math,并指出我忽略的一个更简单的修复?

获胜的代码(以壮观的Java-Heresy(tm)风格)是:

 public static String postFile(String fileName, String userName, String password, String macAddress) throws Exception { HttpClient client = new DefaultHttpClient(); HttpPost post = new HttpPost(SERVER + "uploadFile"); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); final File file = new File(fileName); FileBody fb = new FileBody(file); builder.addPart("file", fb); builder.addTextBody("userName", userName); builder.addTextBody("password", password); builder.addTextBody("macAddress", macAddress); final HttpEntity yourEntity = builder.build(); class ProgressiveEntity implements HttpEntity { @Override public void consumeContent() throws IOException { yourEntity.consumeContent(); } @Override public InputStream getContent() throws IOException, IllegalStateException { return yourEntity.getContent(); } @Override public Header getContentEncoding() { return yourEntity.getContentEncoding(); } @Override public long getContentLength() { return yourEntity.getContentLength(); } @Override public Header getContentType() { return yourEntity.getContentType(); } @Override public boolean isChunked() { return yourEntity.isChunked(); } @Override public boolean isRepeatable() { return yourEntity.isRepeatable(); } @Override public boolean isStreaming() { return yourEntity.isStreaming(); } // CONSIDER put a _real_ delegator into here! @Override public void writeTo(OutputStream outstream) throws IOException { class ProxyOutputStream extends FilterOutputStream { /** * @author Stephen Colebourne */ public ProxyOutputStream(OutputStream proxy) { super(proxy); } public void write(int idx) throws IOException { out.write(idx); } public void write(byte[] bts) throws IOException { out.write(bts); } public void write(byte[] bts, int st, int end) throws IOException { out.write(bts, st, end); } public void flush() throws IOException { out.flush(); } public void close() throws IOException { out.close(); } } // CONSIDER import this class (and risk more Jar File Hell) class ProgressiveOutputStream extends ProxyOutputStream { public ProgressiveOutputStream(OutputStream proxy) { super(proxy); } public void write(byte[] bts, int st, int end) throws IOException { // FIXME Put your progress bar stuff here! out.write(bts, st, end); } } yourEntity.writeTo(new ProgressiveOutputStream(outstream)); } }; ProgressiveEntity myEntity = new ProgressiveEntity(); post.setEntity(myEntity); HttpResponse response = client.execute(post); return getContent(response); } public static String getContent(HttpResponse response) throws IOException { BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); String body = ""; String content = ""; while ((body = rd.readLine()) != null) { content += body + "\n"; } return content.trim(); } # NOTE ADDED LATER: as this blasterpiece gets copied into various code lineages, # The management reminds the peanut gallery that "Java-Heresy" crack was there # for a reason, and (as commented) most of that stuff can be farmed out to off- # the-shelf jar files and what-not. That's for the java lifers to tool up. This # pristine hack shall remain obviousized for education, and for use in a pinch. # What are the odds?? 

不用谢谢Phlip足够的解决scheme。 以下是添加进度条支持的最后一步。 我在AsyncTask中运行它 – 下面的进度使您能够将进度发回到AsyncTask中为AsyncTask中运行的类调用AsyncTask.publishProgress()的方法。 进度条并不完全平滑,但至less会移动。 在序言之后,三星S4上传了一个4MB的图像文件,它正在移动4K块。

  class ProgressiveOutputStream extends ProxyOutputStream { long totalSent; public ProgressiveOutputStream(OutputStream proxy) { super(proxy); totalSent = 0; } public void write(byte[] bts, int st, int end) throws IOException { // FIXME Put your progress bar stuff here! // end is the amount being sent this time // st is always zero and end=bts.length() totalSent += end; progress.publish((int) ((totalSent / (float) totalSize) * 100)); out.write(bts, st, end); } 

首先:非常感谢原来的问题/答案。 由于HttpPost现在已经被弃用了,所以我重新做了一点,使用这篇文章的额外的input,并制作了一个微库: https : //github.com/licryle/HTTPPoster

它包装在一个ASync任务整体; 使用MultipartEntityBuilder&HttpURLConnection,让你听callback。

使用:

  1. 下载和提取
  2. 在您的build.gradle模块文件中,添加依赖项:
 dependencies { compile project(':libs:HTTPPoster') } 
  1. 您需要一个类来实现HttpListener接口,以便您可以收听callback。 它在HTTPListener有四个callback:

    • onStartTransfer
    • onProgress
    • onFailure处
    • onResponse
  2. configurationASyncTask并启动它。 这是一个快速的使用方法:

 HashMap<String, String> mArgs = new HashMap<>(); mArgs.put("lat", "40.712784"); mArgs.put("lon", "-74.005941"); ArrayList<File> aFileList = getMyImageFiles(); HttpConfiguration mConf = new HttpConfiguration( "http://example.org/HttpPostEndPoint", mArgs, aFileList, this, // If this class implements HttpListener null, // Boundary for Entities - Optional 15000 // Timeout in ms for the connection operation 10000, // Timeout in ms for the reading operation ); new HttpPoster().execute(mConf); 

希望可以帮助:)感觉还可以免费提供改进build议! 这是非常近的,我根据需要扩展它。

干杯