6

में प्रगति कॉलबैक के साथ क्लाउडिनरी में एक फोटो अपलोड करना मैं क्लाउडिनरी की ओपन सोर्स लाइब्रेरी को संशोधित करने की कोशिश कर रहा हूं ताकि मैं अपनी तस्वीर के अपलोड की प्रगति को सुन सकूं। लाइब्रेरी क्लास में एक मल्टीपार्ट यूटिलिटी जावा क्लास है जिसे मैंने अपलोड की प्रगति को सुनने के लिए संशोधित किया है। https://github.com/cloudinary/cloudinary_java/blob/master/cloudinary-android/src/main/java/com/cloudinary/android/MultipartUtility.javaएंड्रॉइड: HttpURLConnection

मैं सचमुच इसे संशोधित एक और क्लाउड सेवा CloudFS से कोड जब फ़ाइलें/छवियों आदि अपलोड करने पर काम चल रहा का समर्थन करता है के समान:

https://github.com/bitcasa/CloudFS-Android/blob/master/app/src/main/java/com/bitcasa/cloudfs/api/MultipartUpload.java

संशोधनों से पहले मूल कोड GitHub पर पाया जा सकता है

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); 
      } 

     } 

कोड भाग गया लेकिन प्रगति अपलोड का सही ढंग से मापा नहीं प्रतीत होता है। तस्वीर लगभग 365 केबी थी और अपलोड में एक सेकंड का 10 वां हिस्सा था (मैंने 17: 56: 55.481 पर अपलोड शुरू किया और 17: 56: 55.554 यह किया गया था, यह सिर्फ 0.7 सेकेंड से अधिक है)। मुझे विश्वास नहीं है कि मेरा इंटरनेट कनेक्शन तेज़ है और कम से कम 5 सेकंड लेने की उम्मीद है। मुझे लगता है कि यह क्लाउडिनरी सर्वर पर भेजने के लिए बफर को फोटो लिखने के लिए लगाए गए समय को माप रहा है।

तस्वीर अपलोड करने में लगने वाले समय को मापने के लिए मैं इसे कैसे प्राप्त कर सकता हूं ताकि मैं अपनी प्रगति पट्टी के लिए डेटा का उपयोग कर सकूं?

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 एसडीके उनकी सेवाओं के लिए एंड्रॉयड से एक अहस्ताक्षरित प्रत्यक्ष अपलोड करने के लिए सीधे कनेक्ट कर सकते हैं पाने के लिए बनाने की आवश्यकता होगी उनके सर्वर

संपादित करें:

यह है कि मैं क्या करने की कोशिश की है और यह अभी भी 0 से कूदता है - 0.7 सेकंड में 100% जब अपलोड वास्तव में 7 सेकंड समय में खत्म:

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(); 
    } 

उत्तर

3

वहाँ एक है फ्लश() विधि के उपयोग में समस्या और जब आप कॉलबैक अपडेट करते हैं()।

जब भी आप तस्वीर के हिस्से को पढ़ते हैं तो आप अपने कोड से देख सकते हैं, तो आप इसे आउटपुट बफर में लिखते हैं, लेकिन इसका मतलब यह नहीं है कि यह सर्वर पर भेजा गया है, इसे buffered किया जा सकता है, और बाद में लिखने पर ' सर्वर के लिए एन।

आपके पास प्रत्येक आउटपुटस्ट्रीम.write() के बाद दो विकल्प हैं, या तो आउटपुटस्ट्रीम.फ्लैश() कॉल करें, लेकिन यह अपलोड के प्रदर्शन को मार देगा, क्योंकि आप बफरिंग के लाभ खो देंगे।

या आप अपनी विधि के अंत में outputStream.flush() के बाद अपने अपडेट कॉलबैक() को कॉल कर सकते हैं। क्योंकि आउटपुटस्ट्रीम के बाद।फ्लश() आप निश्चित हैं कि डेटा सर्वर पर है, और प्रगति खत्म हो गई है।

फ्लश के बारे में अधिक जानकारी के लिए इस सूत्र What is the purpose of flush() in Java streams?

+0

आपका दूसरा विकल्प बहुत कम समझ में आता है, क्योंकि वह भी होगा के लिए एक प्रगति संकेतक प्राप्त करने के लिए 100% और मुझे क्या करना कोशिश कर रहा हूँ है का पूरा उद्देश्य पर होना अपलोड करें। मैंने आपके पहले विकल्प की कोशिश की और यह काम नहीं कर रहा है, मैंने यह दिखाने के लिए एक संपादन किया है कि मैंने कोशिश की है कि मैंने कोशिश की है। – Simon

+0

आपको ug__ प्रस्ताव की तरह कुछ करने की आवश्यकता है। आपको थोड़ी देर में फ्लश() को कॉल करना चाहिए :), लेकिन जैसा कि मैं आपके परिवर्तन से देख सकता हूं, यह आपके लिए भी काम नहीं कर रहा है। मुझे इसका परीक्षण करने और आपको बताने की आवश्यकता होगी, लेकिन मुझे 99% यकीन है कि फ्लश() को कॉल करना सही तरीका है। हो सकता है कि आपके कोड के किसी अन्य भाग में समस्या हो। इसका परीक्षण करने की आवश्यकता होगी, जो मैं तुरंत करूँगा। – aleksamarkoni

+0

तकनीकी रूप से, आउटपुटस्ट्रीम पर फ्लश कॉल करना कुछ भी नहीं करेगा क्योंकि दस्तावेज़ कहते हैं कि यह कुछ भी नहीं करता है: https://docs.oracle.com/javase/7/docs/api/java/io/OutputStream.html#flush() I ' मैं इसे डेटाऑटपुटस्ट्रीम पर कास्टिंग कर रहा हूं यह देखने के लिए कि क्या इससे कोई फर्क पड़ता है। यह वास्तव में कोई फर्क नहीं पड़ता है। – Simon

0

देखना यह अंधेरे में एक शॉट है, क्योंकि मैं एक Android पर्यावरण पर परीक्षण नहीं किया, फिर भी मैं निम्नलिखित की कोशिश कर की सिफारिश करेंगे।

इसके बजाय एक निश्चित लंबाई उपयोग setChunkedStreamingMode

//httpConn.setFixedLengthStreamingMode(filesize); 
httpConn.setChunkedStreamingMode(4096); // or whatever size you see fit 

अनुरोध के इस चाहिए ट्रिगर भाग कर का उपयोग करने का

हर बार जब आप डेटा के 4096 बाइट्स और अनिवार्य रूप से आंतरिक बफर बाहर निस्तब्धता में भेजने के लिए भेजा करने के लिए।


आप प्रत्येक लिखने के बाद मैन्युअल रूप से बफर निस्तब्धता की कोशिश कर सकते, यह विशेष रूप से फाइल अपलोड धीमा अगर आप फ्लश अक्सर हालांकि यह संभावना है आपकी समस्या का समाधान होगा सकता है। आप एक मीठा स्थान खोजने के लिए बफर आकार के साथ खेलना समाप्त कर सकते हैं।

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); 
    } 
    // trigger the stream to write its data 
    outputStream.flush(); 
} 
इन परिवर्तनों को आप की संभावना उपयोगकर्ता के बजाय कुल फ़ाइल आकार में गुजर के अपने स्वयं के बफर आकार निर्धारित करने का निर्णय जाने के लिए चाहते हो जाएगा में से किसी के साथ

। ईजी निम्नलिखित करने के लिए अपने निर्माता बदलने के लिए:

MultipartUtility(String requestURL, String charset, 
       String boundary, Map<String, String> headers, int chunkSize) 
+0

मैं setChunkedStreamingMode का उपयोग करने के बारे में थोड़ा परेशान हूं जैसा कि मैंने दस्तावेज़ों में पढ़ा है कि: पुराने HTTP/1.0 केवल सर्वर इस मोड का समर्थन नहीं कर सकते हैं। मुझे नहीं पता कि किस प्रकार का सर्वर क्लाउडिनरी उपयोग कर रहा है, इसलिए यह काम नहीं कर सकता है। फिक्स्ड लम्बाईस्ट्रीमिंगमोड में उस प्रतिबंध को प्रतीत नहीं होता है। वैसे भी, मैंने आपके फ्लश सुझावों को भी आजमाया और यह काम नहीं कर रहा है। मैंने जो देखा है उसे देखने के लिए मेरे प्रश्न में संपादित करें देखें। – Simon

+0

@ सिमॉन दस्तावेज़ीकरण बताता है कि URLConnection कार्यान्वयन आरएफसी 2616 के लिए डिज़ाइन किया गया है जो HTTP/1 है।1 spec, मुझे आश्चर्य होगा कि जिस सर्वर से आप कनेक्ट करने का प्रयास कर रहे हैं वह उस spec का समर्थन नहीं करता क्योंकि यह इन दिनों वेब पर एक मानक है। मैं http://developer.android.com/reference/java/net/HttpURLConnection.html की पहली वाक्य को देख रहा हूं –

संबंधित मुद्दे