Download a multi-page HttpUrlConnection file using progressBar

I want to check the file upload progress on the HttpUrlConnection . How can i do this? I tried to compute the bytes when writing data to an OutputStream , but this is wrong because the real load only happens when conn.getInputStream() called, so I need to check the inputStream somehow. Here is my code:

 public static void uploadMovie(final HashMap<String, String> dataSource, final OnLoadFinishedListener finishedListener, final ProgressListener progressListener) { if (finishedListener != null) { new Thread(new Runnable() { public void run() { try { String boundary = getMD5(dataSource.size()+String.valueOf(System.currentTimeMillis())); MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create(); multipartEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); multipartEntity.setCharset(Charset.forName("UTF-8")); for (String key : dataSource.keySet()) { if (key.equals(MoviesFragmentAdd.USERFILE)) { FileBody userFile = new FileBody(new File(dataSource.get(key))); multipartEntity.addPart(key, userFile); continue; } multipartEntity.addPart(key, new StringBody(dataSource.get(key),ContentType.APPLICATION_JSON)); } HttpEntity entity = multipartEntity.build(); HttpURLConnection conn = (HttpsURLConnection) new URL(URL_API + "/video/addForm/").openConnection(); conn.setUseCaches(false); conn.setDoOutput(true); conn.setDoInput(true); conn.setRequestMethod("POST"); conn.setRequestProperty("Accept-Charset", "UTF-8"); conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("Cache-Control", "no-cache"); conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary); conn.setRequestProperty("Content-length", entity.getContentLength() + ""); conn.setRequestProperty(entity.getContentType().getName(),entity.getContentType().getValue()); OutputStream os = conn.getOutputStream(); entity.writeTo(os); os.close(); //Real upload starting here -->> BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); //<<-- JsonObject request = (JsonObject) gparser.parse(in.readLine()); if (!request.get("error").getAsBoolean()) { //do something } conn.disconnect(); } catch (Exception e) { e.printStackTrace(); } } }).start(); } } 
+6
source share
2 answers

Since you have to deal with loading, I would suggest that when executing entity.writeTo(os); Most of the time. Perhaps the first contact with the server takes some time (DNS resolution, SSL handshake, ...). The tokens you set for "real boot" do not match IMO.

Now it depends on your Multipart library, whether you can intercept writeTo . If it is smart and resource-efficient, it iterates in parts and passes the contents one by one to the output stream. If not, and the .build() operation creates a lot of fat byte[] , you can take this array, pass it to the server chunks and tell your user how many percent of the download has already been completed.

In terms of resources, I would rather not know what is happening. But if feedback is important, and if the films are only a few megabytes in size, you can first transfer the Multipart-Entity object to ByteArrayOutputStream , and then write small fragments of the created byte array to the server, notifying the user about the progress. The following code is not verified and not verified (you can see it as pseudocode):

 ByteArrayOutputStream baos = new ByteArrayOutputStream(); entity.writeTo(baos); baos.close(); byte[] payload = baos.toByteArray(); baos = null; OutputStream os = conn.getOutputStream(); int totalSize = payload.length; int bytesTransferred = 0; int chunkSize = 2000; while (bytesTransferred < totalSize) { int nextChunkSize = totalSize - bytesTransferred; if (nextChunkSize > chunkSize) { nextChunkSize = chunkSize; } os.write(payload, bytesTransferred, nextChunkSize); // TODO check outcome! bytesTransferred += nextChunkSize; // Here you can call the method which updates progress // be sure to wrap it so UI-updates are done on the main thread! updateProgressInfo(100 * bytesTransferred / totalSize); } os.close(); 

A more elegant way would be to write an OutputStream hook that records progress and delegates real write operations to the underlying "real" OutputStream.

Edit

@whizzzkey wrote:

I re-checked it many times - entity.writeTo(os) DOES NOT conn.getResponseCode() load, it does conn.getResponseCode() or conn.getInputStream()

It is now clear. HttpURLConnection buffers your loaded data because it does not know the length of the content. You set the "Content-length" header, but obviously this is ignored by the HUC. You have to call

 conn.setFixedLengthStreamingMode(entity.getContentLength()); 

Then you better remove the call to conn.setRequestProperty("Content-length", entity.getContentLength() + "");

In this case, the HUC can write headers, and entity.writeTo(os) can actually send data to the server. Otherwise, buffered data is sent when the HUC knows how many bytes will be transmitted. Thus, actually getInputStream() tells the HUC that you are done, but before you actually read the answer, all the data collected must be sent to the server.

I would not recommend changing the code, but for those of you who do not know the exact size of the transmitted data (in bytes, not in characters !!), you can tell HUC that it should transfer the data to pieces without setting the exact length of the content:

 conn.setChunkedStreamingMode(-1); // use default chunk size 
+10
source

On the right is this code in your activity ...

public class PublishPostToServer extends AsyncTask ProgressListenerForPost {

  public Context pContext; public long totalSize; private String response; public PublishPostToServer(Context context) { pContext = context; } protected void onPreExecute() { showProgressDialog(); } @Override protected Boolean doInBackground(Void... params) { boolean success = true; try { response = NetworkAdaptor.getInstance() .upLoadMultipartImageToServer( "", "", "", this, this); // Add file path, Authkey, caption } catch (Exception e) { success = false; } return success; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); //validateResponse(result, response); } @Override protected void onProgressUpdate(Integer... values) { try { if (mProgressDialog != null) { mProgressDialog.setProgress(values[0]); } } catch (Exception exception) { } } @Override public void transferred(long num) { publishProgress((int) ((num / (float) totalSize) * 100)); } } private void showProgressDialog() { try { String dialogMsg = "Uploading Image..."; mProgressDialog = new ProgressDialog(this); mProgressDialog.setMessage(dialogMsg); mProgressDialog.setIndeterminate(false); mProgressDialog.setMax(100); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mProgressDialog.setCancelable(false); mProgressDialog.show(); } catch (Exception exception) { } } 

Now make the class NetworkAdapter

public String upLoadMultipartImageToServer (String sourceFileUri, String auth_key, string header, ProgressListenerForPost, PublishPostToServer asyncListiner) {String upLoadServerUri = "+" upload_image ";

  HttpPost httppost = new HttpPost(upLoadServerUri); File file = new File(sourceFileUri); if (file.exists()) { FileBody filebodyVideo = new FileBody(file); CustomMultiPartEntity multipartEntity = new CustomMultiPartEntity( HttpMultipartMode.BROWSER_COMPATIBLE, listiner); try { multipartEntity.addPart("auth_key", new StringBody(auth_key)); multipartEntity.addPart("caption", new StringBody(caption)); multipartEntity.addPart("image", filebodyVideo); asyncListiner.totalSize = multipartEntity.getContentLength(); httppost.setEntity(multipartEntity); } catch (UnsupportedEncodingException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } DefaultHttpClient mHttpClient = new DefaultHttpClient(); String response = ""; try { response = mHttpClient.execute(httppost, new MovieUploadResponseHandler()); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return response; } else { return null; } } @SuppressWarnings("rawtypes") private class MovieUploadResponseHandler implements ResponseHandler { @Override public Object handleResponse(HttpResponse response) throws ClientProtocolException, IOException { HttpEntity r_entity = response.getEntity(); String responseString = EntityUtils.toString(r_entity); // DebugHelper.printData("UPLOAD", responseString); return responseString; } } public static boolean isValidResponse(String resultData) { try { } catch (Exception exception) { //DebugHelper.printException(exception); } return true; } public String upLoadVideoToServer(String currentFilePath, String string, PublishPostToServer publishPostToServer, PublishPostToServer publishPostToServer2) { // TODO Auto-generated method stub return null; } 
-2
source

All Articles