2014-10-17 4 views
1

Я пытаюсь получить ход фактической загрузки файлов с помощью HttpPost. У меня есть стабильное решение до сих пор (которое я нашел здесь в SO), которое имеет прогресс, но после загрузки больших файлов я понял, что он учитывает только байты, записанные в выходной буфер, а не прогресс пост-передачи. Я хотел бы как-то получить ход фактической «должности». Может кто-нибудь объяснить, как я могу достичь этого, используя то, что я так усердно трудился, чтобы получить до сих пор? Большинство решений, которые я нашел в Интернете, учитывают только байты, записанные в выходной буфер (что достаточно для небольших файлов, но не при передаче больших файлов).Получить прогресс загрузки файлов с помощью HttpPost в Android

общественности статической строки postFile (окончательный контекст Context, String имя_файла) бросает исключение {

HttpClient client = new DefaultHttpClient(); 
    HttpPost post = new HttpPost("http://my.url/"); 
    MultipartEntityBuilder builder = MultipartEntityBuilder.create();   
    builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); 

    final File file = new File(fileName); 
    final long totalSize = file.length(); 
    FileBody fb = new FileBody(file); 

    builder.addPart("uploaded_file", new FileBody(new File(fileName))); 


    final HttpEntity yourEntity = builder.build(); 

    int progressPercent = 0; 

    class ProgressiveEntity implements HttpEntity { 
     @Override 
     public void consumeContent() throws IOException { 
      yourEntity.consumeContent();     
     } 
     @Override 
     public InputStream getContent() throws IOException, 
       IllegalStateException { 
      return yourEntity.getContent(); 
     } 
     @Override 
     public Header getContentEncoding() {    
      return yourEntity.getContentEncoding(); 
     } 
     @Override 
     public long getContentLength() { 
      return yourEntity.getContentLength(); 
     } 
     @Override 
     public Header getContentType() { 
      return yourEntity.getContentType(); 
     } 
     @Override 
     public boolean isChunked() {    
      return yourEntity.isChunked(); 
     } 
     @Override 
     public boolean isRepeatable() { 
      return yourEntity.isRepeatable(); 
     } 
     @Override 
     public boolean isStreaming() {    
      return yourEntity.isStreaming(); 
     } // CONSIDER put a _real_ delegator into here! 

     @Override 
     public void writeTo(OutputStream outstream) throws IOException { 

      class ProxyOutputStream extends FilterOutputStream { 

       public ProxyOutputStream(OutputStream proxy) { 
        super(proxy);  
       } 
       public void write(int idx) throws IOException { 
        out.write(idx); 
       } 
       public void write(byte[] bts) throws IOException { 
        out.write(bts); 
       } 
       public void write(byte[] bts, int st, int end) throws IOException { 
        out.write(bts, st, end); 
       } 
       public void flush() throws IOException { 
        out.flush(); 
       } 
       public void close() throws IOException { 
        out.close(); 
       } 
      } // CONSIDER import this class (and risk more Jar File Hell) 

      class ProgressiveOutputStream extends ProxyOutputStream { 
       long totalSent; 
       public ProgressiveOutputStream(OutputStream proxy) { 
         super(proxy); 
         totalSent = 0; 
       } 

       public void write(byte[] bts, int st, int end) throws IOException { 

       // end is the amount being sent this time 
       // st is always zero and end=bts.length() 

        totalSent += end; 
        int progress = (int) ((totalSent/(float) totalSize) * 100); 
        out.write(bts, st, end); 
       } 
      } 

      yourEntity.writeTo(new ProgressiveOutputStream(outstream)); 
     } 

    }; 



    ProgressiveEntity myEntity = new ProgressiveEntity(); 

    post.setEntity(myEntity); 

    //Output to buffer is complete at this point! 
    HttpResponse response = client.execute(post);   

    String jsonResponseStr = getContent(response); 

    Log.d("MYTAG",jsonResponseStr); 

    return jsonResponseStr; 

} 

В моем приемном сценарии на удаленном сервере, я только эхо-ную строку, так что я могу отправить немедленно (вообще никакой обработки файлов и баз данных), а ответ с сервера все еще занимает очень много времени. Я твердо верю, что в этот момент передача происходит после завершения записи в буфер.

+0

Использовать publishProgress(); Проверьте [this] (http://stackoverflow.com/questions/6924447/how-to-implement-file-upload-progress-bar-in-android) – ashutiwari4

+0

@ ashutiwari4 этот ответ также учитывает прогресс записи в буфер, если вы не используйте параметр setfixedlengthstreamingmode, который я не считаю методом любого использования. Я хотел бы избежать переписывания всего, что у меня есть, если это возможно. –

+0

'НЕ прогресс передачи сообщения .'. Что такое прогресс после передачи? – greenapps

ответ

0

Поскольку я не вижу решения для этого, я полагаю, что ответ заключается в использовании вращающейся анимации без процента прогресса. Поскольку ничего не может быть сделано до тех пор, пока передача не будет завершена в любом случае. О, хорошо ... по крайней мере, это решило мою проблему.

+0

Я все еще думаю, что вы говорили о проблеме, которая не существует. – greenapps

+0

Если я представляю это, не могли бы вы объяснить, почему, когда мой прогресс достигнет 100%, загруженный файл только что появился как часть доли всего файла на моем удаленном сервере? И почему ответ сервера не возвращается к клиенту андроида, пока файл на сервере не достигнет своего общего размера? И почему, если я удаляю всю обработку файлов на стороне сервера и возвращаю немедленный ответ, для ответа сервера для достижения клиента все равно требуется столько же времени. Может быть, я ошибаюсь в этом буферизации, но это то, что кажется проблемой для меня. –

+0

'почему после того, как мой прогресс достиг 100%, загруженный файл только что начал отображаться только как часть общего размера файла на моем удаленном сервере?» Это проблемы кэширования и буферизации. Один из них готов к заполнению буферов, а их занятие опустошает их. 'почему ответ сервера не возвращается к андроидному клиенту до тех пор, пока файл на сервере не достигнет своего общего размера?' Потому что сервер только начнет отвечать, когда все «в». Сердце не может даже отправить что-то, прежде чем он прочитает все, поскольку это запрещено протоколом http, о котором я говорил раньше. – greenapps

0

может быть, вы могли бы Промывайте данные при каждом вызове записи:

totalSent += end; 
int progress = (int) ((totalSent/(float) totalSize) * 100); 
out.write(bts, st, end); 
out.flush(); //flush 

Edit: вы также можете попробовать это, так как я получаю конец чувство представляет собой конечный индекс в OutputStream с именем out:

totalSent += (end-st); 
+0

спасибо, я попробовал это, но не заметил никакой разницы с видео 92 МБ. На самом деле я не заметил никакого запаздывания с или без флеш-заявления, поэтому не могу сказать, что это вообще имело значение. –

+0

Я получаю ощущение, что значение 'end' на самом деле не является суммой отправленного, но конечным индексом. Я знаю, что это говорит о том, что amout отправлен в документации, но я думаю, что он представлен как конечный индекс, так что когда вы вызываете 'out.wrtite (bts, st, end),' он обрабатывает его правильно. Я знаю, что это не похоже но вы можете попробовать: 'totalSent + = (end-st);' вместо – Maro

0

Я знаю, что это довольно старый, но я только что нашел решение. Если TotalSize ваша длина содержимого объект, то вы можете основывать свой прогресс на том, что:

class ProgressiveOutputStream extends ProxyOutputStream { 
        long totalSent; 
        long totalSize; 
        public ProgressiveOutputStream(OutputStream proxy, long total) { 
         super(proxy); 
         totalSent = 0; 
         totalSize = total; 
        } 
        public void write(byte[] bts, int st, int end) throws IOException { 
         totalSent += end; 
         publishProgress((int) ((totalSent/(float) totalSize) * 100)); 
         out.write(bts, st, end); 
        } 
       } 

       yourEntity.writeTo(new ProgressiveOutputStream(outstream, yourEntity.getContentLength())); 

Вы обновите прогрессбар в OnProgressUpdate вашего AsyncTask (рь является ProgressBar):

@Override 
    protected void onProgressUpdate(Integer... values) { 
     super.onProgressUpdate(values); 
     pb.setProgress(values[0]); 
    } 
+0

спасибо, но, к сожалению, я использовал Thread вместо AsyncTask, и у меня нет времени прямо сейчас, чтобы попробовать это. Но если мне когда-нибудь понадобится изменить этот кусок, я дам ему шанс. –

0

Пожалуйста, попробуйте Следующее решение вместо того, чтобы использовать ProxyOutputStream в методе writeTo:

@Override 
public void writeTo(OutputStream outstream) throws IOException { 
    ByteArrayInputStream reader = new ByteArrayInputStream(mImageData); 
    byte[] fileBuffer = new byte[2048]; 
    int bytesRead; 
    while ((bytesRead = reader.read(fileBuffer)) != -1) { 
     outstream.write(fileBuffer, 0, bytesRead); 
     int progress = bytesRead; 
    } 
    reader.close(); 
    yourEntity.writeTo(outstream); 
} 
+0

Зачем попробовать это решение вместо этого? –

+0

ОП отметил, что его решение работает неправильно. Я понял, что его решение не учитывает отправленные байты должным образом. Если вы попробуете, вы заметите, что в конечном итоге будет достигнута только половина общего количества байтов. Мое решение возвращает правильное количество отправленных байтов, которое я получаю из метода 'reader.read (fileBuffer)'. – novachevskyi

1
class ProgressiveOutputStream extends ProxyOutputStream { 
      long totalSent; 
      public ProgressiveOutputStream(OutputStream proxy) { 
        super(proxy); 
        totalSent = 0; 
      } 

      public void write(byte[] bts, int st, int end) throws IOException { 

      // FIXME Put your progress bar stuff here! 
      // end is the amount being sent this time 
      // st is always zero and end=bts.length() 

       totalSent += end; 
       progress.publish((int) ((totalSent/(float) totalSize) * 100)); 
       out.write(bts, st, end); 
      }