- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试修改cloudinary的开源库,以便可以监听我的照片上传进度。库类包含一个 MultipartUtility java 类,我对其进行修改以监听上传进度。
修改前的原始代码可以在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 charset, 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, 0, 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, inputStream, "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, 0, 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 网站上创建一个免费帐户以获取您的 cloudname
,这样您就可以将您的 Android SDK 连接到他们的服务,以便从android 直接连接到他们的服务器。
编辑:
这是我尝试过的,当上传实际在 7 秒内完成时,它仍然在 0.7 秒内从 0 跳到 100%:
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, 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();
}
最佳答案
使用flush()方法和调用update callback()的时间有问题
从你的代码可以看出,每次读取图片的一部分时,你都将它写入输出缓冲区,但这并不意味着它已发送到服务器,它可能会被缓冲,然后再写入'n到服务器。
您有两个选择,要么在每个 outputStream.write() 之后调用 outputStream.flush(),但这会降低上传性能,因为您将失去缓冲的好处。
或者您可以在方法末尾的 outputStream.flush() 之后调用 updateCallback()。因为在 outputStream.flush() 之后你确定数据在服务器上了,那个进度就结束了。
有关冲洗的更多信息,请参阅此线程 What is the purpose of flush() in Java streams?
关于java - Android:使用 HttpURLConnection 中的进度回调在 Cloudinary 中上传照片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36826326/
我想做的是让 JTextPane 在 JPanel 中占用尽可能多的空间。对于我使用的 UpdateInfoPanel: public class UpdateInfoPanel extends JP
我在 JPanel 中有一个 JTextArea,我想将其与 JScrollPane 一起使用。我正在使用 GridBagLayout。当我运行它时,框架似乎为 JScrollPane 腾出了空间,但
我想在 xcode 中实现以下功能。 我有一个 View Controller 。在这个 UIViewController 中,我有一个 UITabBar。它们下面是一个 UIView。将 UITab
有谁知道Firebird 2.5有没有类似于SQL中“STUFF”函数的功能? 我有一个包含父用户记录的表,另一个表包含与父相关的子用户记录。我希望能够提取用户拥有的“ROLES”的逗号分隔字符串,而
我想使用 JSON 作为 mirth channel 的输入和输出,例如详细信息保存在数据库中或创建 HL7 消息。 简而言之,输入为 JSON 解析它并输出为任何格式。 最佳答案 var objec
通常我会使用 R 并执行 merge.by,但这个文件似乎太大了,部门中的任何一台计算机都无法处理它! (任何从事遗传学工作的人的附加信息)本质上,插补似乎删除了 snp ID 的 rs 数字,我只剩
我有一个以前可能被问过的问题,但我很难找到正确的描述。我希望有人能帮助我。 在下面的代码中,我设置了varprice,我想添加javascript变量accu_id以通过rails在我的数据库中查找记
我有一个简单的 SVG 文件,在 Firefox 中可以正常查看 - 它的一些包装文本使用 foreignObject 包含一些 HTML - 文本包装在 div 中:
所以我正在为学校编写一个 Ruby 程序,如果某个值是 1 或 3,则将 bool 值更改为 true,如果是 0 或 2,则更改为 false。由于我有 Java 背景,所以我认为这段代码应该有效:
我做了什么: 我在这些账户之间创建了 VPC 对等连接 互联网网关也连接到每个 VPC 还配置了路由表(以允许来自双方的流量) 情况1: 当这两个 VPC 在同一个账户中时,我成功测试了从另一个 La
我有一个名为 contacts 的表: user_id contact_id 10294 10295 10294 10293 10293 10294 102
我正在使用 Magento 中的新模板。为避免重复代码,我想为每个产品预览使用相同的子模板。 特别是我做了这样一个展示: $products = Mage::getModel('catalog/pro
“for”是否总是检查协议(protocol)中定义的每个函数中第一个参数的类型? 编辑(改写): 当协议(protocol)方法只有一个参数时,根据该单个参数的类型(直接或任意)找到实现。当协议(p
我想从我的 PHP 代码中调用 JavaScript 函数。我通过使用以下方法实现了这一点: echo ' drawChart($id); '; 这工作正常,但我想从我的 PHP 代码中获取数据,我使
这个问题已经有答案了: Event binding on dynamically created elements? (23 个回答) 已关闭 5 年前。 我有一个动态表单,我想在其中附加一些其他 h
我正在尝试找到一种解决方案,以在 componentDidMount 中的映射项上使用 setState。 我正在使用 GraphQL连同 Gatsby返回许多 data 项目,但要求在特定的 pat
我在 ScrollView 中有一个 View 。只要用户按住该 View ,我想每 80 毫秒调用一次方法。这是我已经实现的: final Runnable vibrate = new Runnab
我用 jni 开发了一个 android 应用程序。我在 GetStringUTFChars 的 dvmDecodeIndirectRef 中得到了一个 dvmabort。我只中止了一次。 为什么会这
当我到达我的 Activity 时,我调用 FragmentPagerAdapter 来处理我的不同选项卡。在我的一个选项卡中,我想显示一个 RecyclerView,但他从未出现过,有了断点,我看到
当我按下 Activity 中的按钮时,会弹出一个 DialogFragment。在对话框 fragment 中,有一个看起来像普通 ListView 的 RecyclerView。 我想要的行为是当
我是一名优秀的程序员,十分优秀!