问题
I am trying to send a file to server using Multipart. This is how I am sending the request
MultipartRequest request = new MultipartRequest(putURLPath,
hashMap,
null,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
try {
Log.d(TAG, "FILE_UPLOAD_RESPONSE: " + response);
Logger.writeToFile(TAG, "FILE_UPLOAD_RESPONSE: " + response);
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(false, getURLPath), message, isRetry);
// fileDownload(getURLPath);
} catch (Exception e) {
e.printStackTrace();
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Logger.writeToFile(TAG, "FILE_UPLOAD_RESPONSE--Error: " + error.getMessage());
/* byte[] bytes = ((NetworkResponse)((AuthFailureError)error).networkResponse).data;
WAAFILogger.d(TAG, "XML: " + bytes.);*/
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
error.printStackTrace();
}
}, new IMultipartProgressListener() {
@Override
public void transferred(long transferred, int progress) {
WAAFILogger.d(TAG, "Transferred : " + transferred + "\n" + " Progress : " + progress);
try {
if (fileUploadListener != null) {
fileUploadListener.onProgressChanged(message, progress);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, bytesArray) {
@Override
public String getBodyContentType() {
return fileInfo.fileMimeType;
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("content-length", String.valueOf(bytesArray.length));
params.put("host", IMConstant.XMPP_SERVER + ":9000");
Logger.writeToFile(TAG, params.get("content-length"));
Logger.writeToFile(TAG, params.get("host"));
return params;
}
};
request.setRetryPolicy(com.safarifone.settings.Settings.policy);
VolleyQueManager.getInstance().addToRequestQueue(request);
I have used a custom request and the link is here Custom Request Repo Link and the code is below
public class MultipartRequest extends Request<String> {
private final byte[] byteArray;
MultipartEntityBuilder entity = MultipartEntityBuilder.create();
// CounterHttpEntity httpentity;
HttpEntity httpentity;
// CountingHttpEntity httpentity;
private FileUploadManager.IMultipartProgressListener mProgressListener;
private final Response.Listener<String> mListener;
private HashMap<String, File> mFiles;
private HashMap<String, String> mBody;
private long fileLength = 0L;
public MultipartRequest(String url,
HashMap<String, File> mFiles,
HashMap<String, String> body,
Response.Listener<String> listener,
Response.ErrorListener errorListener,
FileUploadManager.IMultipartProgressListener progressListener, byte[] bytesArray) {
super(Method.PUT, url, errorListener);
this.mListener = listener;
this.mFiles = mFiles;
this.mBody = body;
this.fileLength = /*getFileLength()*/ bytesArray.length;
this.mProgressListener = progressListener;
this.byteArray = bytesArray;
entity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
try {
entity.setCharset(CharsetUtils.get("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
buildMultipartEntity();
httpentity = entity.build();
/*httpentity.setFileLength(fileLength);
httpentity.setmProgressListener(progressListener);*/
}
private void buildMultipartEntity() {
for (Map.Entry<String, File> entry : mFiles.entrySet()) {
if (entry.getValue() != null) {
entity.addPart(entry.getKey(), new FileBody(entry.getValue()));
}
}
if (mBody != null) {
for (Map.Entry<String, String> entry : mBody.entrySet()) {
if (entry.getValue() != null) {
entity.addTextBody(entry.getKey(), entry.getValue());
}
}
}
}
private int getFileLength() {
int lgth = 0;
for (Map.Entry<String, File> entry : mFiles.entrySet()) {
if (entry.getValue() != null) {
lgth += entry.getValue().length();
}
}
System.out.println("lgth = " + lgth);
return lgth;
}
@Override
public String getBodyContentType() {
return super.getBodyContentType();
/*return httpentity.getContentType().getValue();*/
}
@Override
public byte[] getBody() throws AuthFailureError {
Thread thread = new Thread() {
@Override
public void run() {
super.run();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
bos.write(byteArray, 0, byteArray.length);
httpentity.writeTo(new CountingOutputStream(bos, fileLength,
mProgressListener));
} catch (IOException e) {
VolleyLog.e("IOException writing to ByteArrayOutputStream");
}
}
};
thread.start();
return /*bos.toByteArray()*/ byteArray;
}
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(jsonString,
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(String response) {
mListener.onResponse(response);
}
public static class CountingOutputStream extends FilterOutputStream {
private final FileUploadManager.IMultipartProgressListener progressListener;
private long transferred;
private long fileLength;
private int lastProgress = 0;
public CountingOutputStream(final OutputStream out, long fileLength,
final FileUploadManager.IMultipartProgressListener listener) {
super(out);
this.fileLength = fileLength;
this.progressListener = listener;
this.transferred = 0;
}
public void write(byte[] buffer, int offset, int length) throws IOException {
out.write(buffer, offset, length);
if (progressListener != null) {
this.transferred += length;
int progress = (int) ((transferred * 1000.0f) / fileLength);
if (lastProgress != progress) {
this.progressListener.transferred(this.transferred, progress);
}
}
}
public void write(int oneByte) throws IOException {
out.write(oneByte);
if (progressListener != null) {
this.transferred++;
int progress = (int) ((transferred * 1000.0f) / fileLength);
if (lastProgress != progress) {
this.progressListener.transferred(this.transferred, progress);
}
}
}
}
}
as you can see I am calulating the progress in the function -> write of class CountingOutputStream. But the issue i am facing is that the write function calls too fast and due to this progress bar updates fast but the response of successfully file uploaded took long time even after the progress bar is completed. My guess is that write function fast therefore progress bar is updated but somehow file is not uploading that fast due to which it is still taking time after completed progress.
回答1:
At then at the end, after days of searching I found this piece of code which work fine. As you can see I have added Content-type, Content-Length and host in headers. You can leave those if your server doesnot need these. Especially this
((HttpURLConnection) urlconnection).setFixedLengthStreamingMode((int) fileInfo.fileSize);
line helps me in achieving the real thing i wanted to achieve. It helps me in writing the data on server and then progress according to then again write some data to server and then again update the progress. So this is most important line.
public void main(FileInfo fileInfo, String put, String get, Message message, boolean isRetry) {
URLConnection urlconnection = null;
try {
File file = new File(fileInfo.filePath);
URL url = new URL(put);
urlconnection = url.openConnection();
urlconnection.setDoOutput(true);
urlconnection.setDoInput(true);
if (urlconnection instanceof HttpURLConnection) {
((HttpURLConnection) urlconnection).setRequestMethod("PUT");
((HttpURLConnection) urlconnection).setFixedLengthStreamingMode((int) fileInfo.fileSize);
((HttpURLConnection) urlconnection).setRequestProperty("Content-type", fileInfo.fileMimeType);
((HttpURLConnection) urlconnection).setRequestProperty("Content-length", String.valueOf(fileInfo.fileSize));
((HttpURLConnection) urlconnection).setRequestProperty("host", XMPP_SERVER);
((HttpURLConnection) urlconnection).connect();
}
BufferedOutputStream bos = new BufferedOutputStream(urlconnection.getOutputStream());
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
long transferred = 0;
int i = 0;
byte[] buffer = new byte[4096];
while ((i = bis.read(buffer)) > 0) {
bos.write(buffer, 0, i);
transferred += i;
int progress = (int) ((transferred * 1000.0f) / fileInfo.fileSize);
if (fileUploadListener != null) {
fileUploadListener.onProgressChanged(message, progress);
}
}
bis.close();
bos.close();
InputStream inputStream;
int responseCode = ((HttpURLConnection) urlconnection).getResponseCode();
if ((responseCode >= 200) && (responseCode <= 202)) {
inputStream = ((HttpURLConnection) urlconnection).getInputStream();
int j;
while ((j = inputStream.read()) > 0) {
System.out.println(j);
}
if (responseCode == 200) {
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(false, get), message, isRetry);
} else {
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
}
} else {
inputStream = ((HttpURLConnection) urlconnection).getErrorStream();
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
}
((HttpURLConnection) urlconnection).disconnect();
} catch (Exception e) {
e.printStackTrace();
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
}
}
来源:https://stackoverflow.com/questions/61137778/multipart-file-progress-updating-faster-than-actual-upload