问题
I am using the following code to upload a photo to my server with MultipartEntityBuilder. Somewhere at the end it says // FIXME Put your progress bar stuff here!
. I don't know if I should put the whole function into an Asynctask or what I should do to display progress while the file is uploaded.
I checked Upload a file through an HTTP form, via MultipartEntityBuilder, with a progress bar but it doesn't really help.
public String postFile(String fileName) throws Exception {
fileName = "/mnt/sdcard/DCIM/100MEDIA/IMAG0309.jpg";
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("http://www.mywebsite.com/upload_file.php");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
final File file = new File(fileName);
FileBody fb = new FileBody(file);
builder.addPart("file",fb);
String userid = session_userid;
builder.addTextBody("userID", userid);
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 {
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();
}
}
class ProgressiveOutputStream extends ProxyOutputStream {
int totalSent;
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);
}
Here is what I did but I still need you guys for finishing it:
@Override
protected String doInBackground(HttpResponse... arg0)
{
String fileName = "/mnt/sdcard/DCIM/100MEDIA/IMAG0309.jpg";
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("http://www.mywebsite.com/upload_file.php");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
final File file = new File(fileName);
FileBody fb = new FileBody(file);
builder.addPart("file",fb);
String userid = session_userid;
builder.addTextBody("userID", userid);
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 {
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();
}
}
class ProgressiveOutputStream extends ProxyOutputStream {
public ProgressiveOutputStream(OutputStream proxy) {
super(proxy);
int totalSent = 0;
}
public void write(byte[] bts, int st, int end) throws IOException {
// FIXME Put your progress bar stuff here!
//what's totalSize?
publishProgress((int) ((end / (float) totalSize) * 100));
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);
//Here it says I should put this into a try catch but then I get an error on
// the doInBackground line saying it needs to return a string
}
protected void onProgressUpdate(Integer... progress) {
pd.setProgress((int) (progress[0]));
}
@SuppressWarnings("deprecation")
@Override
protected void onPostExecute(String file_url) {
pd.dismiss();
connection.disconnect();
Toast.makeText(getApplicationContext(), "Ready.", Toast.LENGTH_LONG).show();
}
}
回答1:
I was trying to achieve something similar (I use ProgressDialog
instead of ProgressBar
). You have to use AsyncTask
so the main thread won't be waiting for your upload to finish (Upload must be asynchronous).
Create a extension for
HttpEntityWrapped
(credits: here):public class MyHttpEntity extends HttpEntityWrapper { private ProgressListener progressListener; public MyHttpEntity(final HttpEntity entity, final ProgressListener progressListener) { super(entity); this.progressListener = progressListener; } @Override public void writeTo(OutputStream outStream) throws IOException { this.wrappedEntity.writeTo(outStream instanceof ProgressOutputStream ? outStream : new ProgressOutputStream(outStream, this.progressListener, this.getContentLength())); } public static interface ProgressListener { void transferred(float progress); } public static class ProgressOutputStream extends FilterOutputStream { private final ProgressListener progressListener; private long transferred; private long total; public ProgressOutputStream(final OutputStream outputStream, final ProgressListener progressListener, long total) { super(outputStream); this.progressListener = progressListener; this.transferred = 0; this.total = total; } @Override public void write(byte[] buffer, int offset, int length) throws IOException { out.write(buffer, offset, length); this.transferred += length; this.progressListener.transferred(this._getCurrentProgress()); } @Override public void write(byte[] buffer) throws IOException { out.write(buffer); this.transferred++; this.progressListener.transferred(this._getCurrentProgress()); } private float _getCurrentProgress() { return ((float) this.transferred / this.total) * 100; } }
}
I've created private class that extends
AsyncTask
in anActivity
. IndoInBackground
you useMultipartEntityBuilder
to add your file and anything you want. If upload is successful (code == 200, it's my custom json response),onPostExecute
will be called.private class UploadAsyncTask extends AsyncTask {
private Context context; private Exception exception; private ProgressDialog progressDialog; private UploadAsyncTask(Context context) { this.context = context; } @Override protected Boolean doInBackground(String... params) { String uploadUrl = URL + "upload"; HttpResponse response = null; try { HttpPost post = new HttpPost(uploadUrl); // Entity MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create(); // Add your file multipartEntityBuilder.addPart("file", new FileBody(new File(params[0]))); // Progress listener - updates task's progress MyHttpEntity.ProgressListener progressListener = new MyHttpEntity.ProgressListener() { @Override public void transferred(float progress) { UploadAsyncTask.this.publishProgress((int) progress); } }; // POST post.setEntity(new MyHttpEntity(multipartEntityBuilder.build(), progressListener)); // Handle response GsonBuilder builder = new GsonBuilder(); LinkedTreeMap object = builder.create().fromJson( EntityUtils.toString(client.execute(post).getEntity()), LinkedTreeMap.class); if ((double) object.get("code") == 200.0) { return true; } } catch (UnsupportedEncodingException | JsonSyntaxException | ClientProtocolException e) { e.printStackTrace(); Log.e("UPLOAD", e.getMessage()); this.exception = e; } catch (IOException e) { e.printStackTrace(); } return false; } @Override protected void onPreExecute() { // Init and show dialog this.progressDialog = new ProgressDialog(this.context); this.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); this.progressDialog.show(); } @Override protected void onPostExecute(Boolean result) { // Close dialog this.progressDialog.dismiss(); if (result) { Toast.makeText(getApplicationContext(), R.string.upload_success, Toast.LENGTH_LONG).show(); } else { Toast.makeText(getApplicationContext(), R.string.upload_failure, Toast.LENGTH_LONG).show(); } } @Override protected void onProgressUpdate(Integer... progress) { // Update process this.progressDialog.setProgress((int) progress[0]); }
}
Call upload within a
Acitvity
:private void _upload() {
UploadAsyncTask task = new UploadAsyncTask(this); task.execute();
}
来源:https://stackoverflow.com/questions/22920528/multipartentitybuilder-with-progressbar