android-通过MultipartEntityBuilder通过HTTP表单上传文件,并显示进度b
短版本-.jar已弃用,其升级版本java.lang.NoClassDefFoundError在我们的在线论坛中表示不足。 让我们修复它。 如何注册回调,以便我的(Android)应用在上传文件时可以显示进度栏?
长版-这是.jar的“缺少污垢的简单示例”:
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!
我们需要修复.jar。(一个额外的好处是可中断的上传。)但是(请纠正我,是否我错了),所有在线示例似乎都不够。
例如,这个[http://pastebin.com/M0uNZ6SB]将文件上传为“二进制/八位字节流”; 不是“多部分/表单数据”。 我需要真实的领域。
此示例“使用Java上传文件”(带有进度条)显示了如何覆盖.jar或java.lang.NoClassDefFoundError。因此,也许我可以告诉writeTo到.create()用来衡量其上传进度的覆盖实体?
因此,如果我想覆盖某些内容,并用每1000个字节发送一个信号的计数流替换内置流,也许我可以扩展.jar部分,并覆盖其java.lang.NoClassDefFoundError和/或writeTo。
但是当我尝试.jar时,我得到了臭名昭著的java.lang.NoClassDefFoundError。
因此,当我在.jar文件中搜寻时,寻找丢失的Def,有人可以检查我的数学,并指出我忽略的更简单的修复方法吗?
3个解决方案
67 votes
获胜的代码(采用壮观的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 answered 2020-07-08T17:13:30Z
6 votes
非常感谢Phlip提供该解决方案。 这是添加进度条支持的最后说明。 我在AsyncTask中运行了它-下面的进度使您可以将进度回发到AsyncTask中的方法,该方法为在AsyncTask中运行的类调用AsyncTask.publishProgress()。 进度条并不完全平滑,但至少可以移动。 在三星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);
}
Mike Kogan answered 2020-07-08T17:13:51Z
2 votes
首先:非常感谢您提出的原始问题/答案。 由于HttpPost现在已被弃用,因此我使用本文的其他输入对其进行了一些重做,并制作了一个微型库:[https://github.com/licryle/HTTPPoster]
它将整体包装在ASync任务中; 使用MultipartEntityBuilder和HttpURLConnection,让我们听回调。
使用方法:
下载并解压缩
在您的build.gradle模块文件中,添加依赖项:
dependencies
{
compile project(':libs:HTTPPoster')
}
您需要一个类来实现HttpListener接口,以便可以侦听回调。 它在HTTPListener中有四个回调:
onStartTransfer
onProgress
失败
onResponse
配置ASyncTask并启动它。 快速用法:
HashMap mArgs = new HashMap<>();
mArgs.put("lat", "40.712784");
mArgs.put("lon", "-74.005941");
ArrayList 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);
希望能对您有所帮助:)也可以提出改进建议! 这是最近的事,我会根据需要进行扩展。
干杯
licryle answered 2020-07-08T17:15:04Z