修改前的原始代码可以在github:https://github.com/cloudinary/cloudinary_java/blob/master/cloudinary-android/src/main/java/com/cloudinary/android/MultipartUtility.java上找到
我将其修改为类似于另一个云服务CloudFS的代码,该代码在上传文件/图像等时支持进度:
package com.cloudinary.android; import com.cloudinary.Cloudinary; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; /** * This utility class provides an abstraction layer for sending multipart HTTP * POST requests to a web server. * * @author www.codejava.net * @author Cloudinary */ public class MultipartUtility { private final String boundary; private static final String LINE_Feed = "\r\n"; private static final String APPLICATION_OCTET_STREAM = "application/octet-stream"; private HttpURLConnection httpConn; private String charset; private OutputStream outputStream; private PrintWriter writer; UploadingCallback uploadingCallback; public final static String USER_AGENT = "CloudinaryAndroid/" + Cloudinary.VERSION; Long filesize; public void setUploadingCallback(UploadingCallback uploadingCallback) { this.uploadingCallback = uploadingCallback; } /** * This constructor initializes a new HTTP POST request with content type is * set to multipart/form-data * * @param requestURL * @param charset * @throws IOException */ public MultipartUtility(String requestURL,String charset,String boundary,Map<String,String> headers,Long filesize) throws IOException { this.charset = charset; this.boundary = boundary; this.filesize = filesize; URL url = new URL(requestURL); httpConn = (HttpURLConnection) url.openConnection(); httpConn.setDoOutput(true); // indicates POST method httpConn.setDoInput(true); httpConn.setFixedLengthStreamingMode(filesize); //added this in if (headers != null) { for (Map.Entry<String,String> header : headers.entrySet()) { httpConn.setRequestProperty(header.getKey(),header.getValue()); } } httpConn.setRequestProperty("Content-Type","multipart/form-data; boundary=" + boundary); httpConn.setRequestProperty("User-Agent",USER_AGENT); outputStream = httpConn.getOutputStream(); writer = new PrintWriter(new OutputStreamWriter(outputStream,charset),true); } public MultipartUtility(String requestURL,String boundary) throws IOException { this(requestURL,charset,boundary,null,0L); } /** * Adds a form field to the request * * @param name field name * @param value field value */ public void addFormField(String name,String value) { writer.append("--" + boundary).append(LINE_Feed); writer.append("Content-Disposition: form-data; name=\"" + name + "\"").append(LINE_Feed); writer.append("Content-Type: text/plain; charset=" + charset).append(LINE_Feed); writer.append(LINE_Feed); writer.append(value).append(LINE_Feed); writer.flush(); } /** * Adds a upload file section to the request * * @param fieldName name attribute in {@code <input type="file" name="..." />} * @param uploadFile a File to be uploaded * @throws IOException */ public void addFilePart(String fieldName,File uploadFile,String fileName) throws IOException { if (fileName == null) fileName = uploadFile.getName(); FileInputStream inputStream = new FileInputStream(uploadFile); addFilePart(fieldName,inputStream,fileName); } public void addFilePart(String fieldName,File uploadFile) throws IOException { addFilePart(fieldName,uploadFile,"file"); } public void addFilePart(String fieldName,InputStream inputStream,String fileName) throws IOException { if (fileName == null) fileName = "file"; writer.append("--" + boundary).append(LINE_Feed); writer.append("Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"" + fileName + "\"").append(LINE_Feed); writer.append("Content-Type: ").append(APPLICATION_OCTET_STREAM).append(LINE_Feed); writer.append("Content-Transfer-Encoding: binary").append(LINE_Feed); writer.append(LINE_Feed); writer.flush(); int progress = 0; byte[] buffer = new byte[4096]; int bytesRead = -1; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer,bytesRead); progress += bytesRead; /* int percentage = ((progress / filesize.intValue()) * 100);*/ if (uploadingCallback != null) { uploadingCallback.uploadListener(progress); } } outputStream.flush(); writer.flush(); uploadingCallback = null; inputStream.close(); writer.append(LINE_Feed); writer.flush(); } public void addFilePart(String fieldName,InputStream inputStream) throws IOException { addFilePart(fieldName,"file"); } /** * Completes the request and receives response from the server. * * @return a list of Strings as response in case the server returned status * OK,otherwise an exception is thrown. * @throws IOException */ public HttpURLConnection execute() throws IOException { writer.append("--" + boundary + "--").append(LINE_Feed); writer.close(); return httpConn; } }
我所做的更改是按照此线程的建议将以下内容添加到httpURLConnection:How to implement file upload progress bar in android:httpConn.setFixedLengthStreamingMode(filesize);
然后我创建了一个简单的界面来监听上传进度:
public interface UploadingCallback { void uploadListener(int progress); }
然后我在HttpURLConnection写下照片时附上它:
while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer,bytesRead); progress += bytesRead; /* int percentage = ((progress / filesize.intValue()) * 100);*/ if (uploadingCallback != null) { uploadingCallback.uploadListener(progress); } }
代码已运行,但上传的进度似乎没有正确测量.这张照片大概是365kb,上传时间大约是十分之一秒(我开始上传时间为17:56:55.481,17:56:55.554已完成上传,这只是超过0.7秒).我不相信我的互联网连接速度很快,并且预计它至少需要5秒钟.我感觉它正在测量将照片写入缓冲区所花费的时间,而不是将它发送到cloudinary服务器所花费的时间.
我怎样才能测量上传照片所需的时间,以便我可以将数据用于进度条?
04-24 17:56:55.481 28306-28725/com.a upload 4096 04-24 17:56:55.486 28306-28725/com.a upload 8192 04-24 17:56:55.486 28306-28725/com.a upload 12288 04-24 17:56:55.486 28306-28725/com.a upload 16384 04-24 17:56:55.487 28306-28725/com.a upload 20480 04-24 17:56:55.487 28306-28725/com.a upload 24576 04-24 17:56:55.487 28306-28725/com.a upload 28672 04-24 17:56:55.487 28306-28725/com.a upload 32768 04-24 17:56:55.491 28306-28725/com.a upload 36864 04-24 17:56:55.492 28306-28725/com.a upload 40960 04-24 17:56:55.493 28306-28725/com.a upload 45056 04-24 17:56:55.493 28306-28725/com.a upload 49152 04-24 17:56:55.493 28306-28725/com.a upload 53248 04-24 17:56:55.493 28306-28725/com.a upload 57344 04-24 17:56:55.494 28306-28725/com.a upload 61440 04-24 17:56:55.494 28306-28725/com.a upload 65536 04-24 17:56:55.494 28306-28725/com.a upload 69632 04-24 17:56:55.494 28306-28725/com.a upload 73728 04-24 17:56:55.494 28306-28725/com.a upload 77824 04-24 17:56:55.495 28306-28725/com.a upload 81920 04-24 17:56:55.495 28306-28725/com.a upload 86016 04-24 17:56:55.495 28306-28725/com.a upload 90112 04-24 17:56:55.495 28306-28725/com.a upload 94208 04-24 17:56:55.495 28306-28725/com.a upload 98304 04-24 17:56:55.495 28306-28725/com.a upload 102400 04-24 17:56:55.495 28306-28725/com.a upload 106496 04-24 17:56:55.496 28306-28725/com.a upload 110592 04-24 17:56:55.496 28306-28725/com.a upload 114688 04-24 17:56:55.496 28306-28725/com.a upload 118784 04-24 17:56:55.497 28306-28725/com.a upload 122880 04-24 17:56:55.498 28306-28725/com.a upload 126976 04-24 17:56:55.498 28306-28725/com.a upload 131072 04-24 17:56:55.498 28306-28725/com.a upload 135168 04-24 17:56:55.498 28306-28725/com.a upload 139264 04-24 17:56:55.499 28306-28725/com.a upload 143360 04-24 17:56:55.506 28306-28725/com.a upload 147456 04-24 17:56:55.510 28306-28725/com.a upload 151552 04-24 17:56:55.510 28306-28725/com.a upload 155648 04-24 17:56:55.514 28306-28725/com.a upload 159744 04-24 17:56:55.515 28306-28725/com.a upload 163840 04-24 17:56:55.517 28306-28725/com.a upload 167936 04-24 17:56:55.517 28306-28725/com.a upload 172032 04-24 17:56:55.518 28306-28725/com.a upload 176128 04-24 17:56:55.518 28306-28725/com.a upload 180224 04-24 17:56:55.518 28306-28725/com.a upload 184320 04-24 17:56:55.519 28306-28725/com.a upload 188416 04-24 17:56:55.519 28306-28725/com.a upload 192512 04-24 17:56:55.519 28306-28725/com.a upload 196608 04-24 17:56:55.519 28306-28725/com.a upload 200704 04-24 17:56:55.520 28306-28725/com.a upload 204800 04-24 17:56:55.525 28306-28725/com.a upload 208896 04-24 17:56:55.526 28306-28725/com.a upload 212992 04-24 17:56:55.527 28306-28725/com.a upload 217088 04-24 17:56:55.530 28306-28725/com.a upload 221184 04-24 17:56:55.530 28306-28725/com.a upload 225280 04-24 17:56:55.530 28306-28725/com.a upload 229376 04-24 17:56:55.530 28306-28725/com.a upload 233472 04-24 17:56:55.530 28306-28725/com.a upload 237568 04-24 17:56:55.531 28306-28725/com.a upload 241664 04-24 17:56:55.532 28306-28725/com.a upload 245760 04-24 17:56:55.532 28306-28725/com.a upload 249856 04-24 17:56:55.532 28306-28725/com.a upload 253952 04-24 17:56:55.533 28306-28725/com.a upload 258048 04-24 17:56:55.533 28306-28725/com.a upload 262144 04-24 17:56:55.535 28306-28725/com.a upload 266240 04-24 17:56:55.540 28306-28725/com.a upload 270336 04-24 17:56:55.540 28306-28725/com.a upload 274432 04-24 17:56:55.541 28306-28725/com.a upload 278528 04-24 17:56:55.541 28306-28725/com.a upload 282624 04-24 17:56:55.543 28306-28725/com.a upload 286720 04-24 17:56:55.545 28306-28725/com.a upload 290816 04-24 17:56:55.545 28306-28725/com.a upload 294912 04-24 17:56:55.547 28306-28725/com.a upload 299008 04-24 17:56:55.547 28306-28725/com.a upload 303104 04-24 17:56:55.547 28306-28725/com.a upload 307200 04-24 17:56:55.547 28306-28725/com.a upload 311296 04-24 17:56:55.547 28306-28725/com.a upload 315392 04-24 17:56:55.548 28306-28725/com.a upload 319488 04-24 17:56:55.548 28306-28725/com.a upload 323584 04-24 17:56:55.548 28306-28725/com.a upload 327680 04-24 17:56:55.548 28306-28725/com.a upload 331776 04-24 17:56:55.549 28306-28725/com.a upload 335872 04-24 17:56:55.549 28306-28725/com.a upload 339968 04-24 17:56:55.549 28306-28725/com.a upload 344064 04-24 17:56:55.550 28306-28725/com.a upload 348160 04-24 17:56:55.550 28306-28725/com.a upload 352256 04-24 17:56:55.551 28306-28725/com.a upload 356352 04-24 17:56:55.551 28306-28725/com.a upload 360448 04-24 17:56:55.552 28306-28725/com.a upload 364544 04-24 17:56:55.554 28306-28725/com.a upload 365790
要自己测试一下,您需要在cloudinary网站上创建一个免费帐户以获取您的云端名称,这样您就可以将Android SDK连接到他们的服务,从而直接从Android直接上传到他们的服务器.
编辑:
这是我尝试过的,当上传实际在7秒内完成时,它仍然会在0.7秒内从0 – 100%跳跃:
while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer,bytesRead); progress += bytesRead; Log.d("MultiPart","file transferred so far: " + progress); if (uploadingCallback != null) { uploadingCallback.uploadListener(progress); } Log.d("Flushing","flush the writer"); outputStream.flush(); writer.flush(); }
解决方法
每次读取部分图片时都可以从代码中看到,将其写入输出缓冲区,但这并不意味着它被发送到服务器,它可能被缓冲,然后写入服务器.
你有两个选择,在每个outputStream.write()之后调用outputStream.flush(),但这会杀死上传的性能,因为你会失去缓冲的好处.
或者,您可以在方法结束时的outputStream.flush()之后调用updateCallback().因为在outputStream.flush()之后,您确定数据在服务器上,并且该进度已结束.
有关flush的更多信息,请参阅此主题What is the purpose of flush() in Java streams?