2010-04-08 8 views
6

Mam ten sam problem as described here, ale podam jeszcze kilka szczegółów. Próbując przesłać wideo w systemie Android, czytam je do pamięci, a jeśli wideo jest duże, otrzymuję komunikat OutOfMemoryError.Android: OutOfMemoryError podczas przesyłania wideo - jak najlepiej porwać?

Oto mój kod:

// get bytestream to upload 
videoByteArray = getBytesFromFile(cR, fileUriString); 

public static byte[] getBytesFromFile(ContentResolver cR, String fileUriString) throws IOException { 
    Uri tempuri = Uri.parse(fileUriString); 
    InputStream is = cR.openInputStream(tempuri); 
    byte[] b3 = readBytes(is); 
    is.close(); 
    return b3; 
} 
public static byte[] readBytes(InputStream inputStream) throws IOException { 
    ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); 
    // this is storage overwritten on each iteration with bytes 
    int bufferSize = 1024; 
    byte[] buffer = new byte[bufferSize]; 
    int len = 0; 
    while ((len = inputStream.read(buffer)) != -1) { 
     byteBuffer.write(buffer, 0, len); 
    } 
    return byteBuffer.toByteArray(); 
} 

A oto traceback (błąd zostanie rzucony na linii byteBuffer.write(buffer, 0, len)):

04-08 11:56:20.456: ERROR/dalvikvm-heap(6088): Out of memory on a 16775184-byte allocation. 
04-08 11:56:20.456: INFO/dalvikvm(6088): "IntentService[UploadService]" prio=5 tid=17 RUNNABLE 
04-08 11:56:20.456: INFO/dalvikvm(6088): | group="main" sCount=0 dsCount=0 s=N obj=0x449a3cf0 self=0x38d410 
04-08 11:56:20.456: INFO/dalvikvm(6088): | sysTid=6119 nice=0 sched=0/0 cgrp=default handle=4010416 
04-08 11:56:20.456: INFO/dalvikvm(6088): at java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java:~93) 
04-08 11:56:20.456: INFO/dalvikvm(6088): at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:218) 
04-08 11:56:20.456: INFO/dalvikvm(6088): at com.android.election2010.UploadService.readBytes(UploadService.java:199) 
04-08 11:56:20.456: INFO/dalvikvm(6088): at com.android.election2010.UploadService.getBytesFromFile(UploadService.java:182) 
04-08 11:56:20.456: INFO/dalvikvm(6088): at com.android.election2010.UploadService.doUploadinBackground(UploadService.java:118) 
04-08 11:56:20.456: INFO/dalvikvm(6088): at com.android.election2010.UploadService.onHandleIntent(UploadService.java:85) 
04-08 11:56:20.456: INFO/dalvikvm(6088): at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:30) 
04-08 11:56:20.456: INFO/dalvikvm(6088): at android.os.Handler.dispatchMessage(Handler.java:99) 
04-08 11:56:20.456: INFO/dalvikvm(6088): at android.os.Looper.loop(Looper.java:123) 
04-08 11:56:20.456: INFO/dalvikvm(6088): at android.os.HandlerThread.run(HandlerThread.java:60) 
04-08 11:56:20.467: WARN/dalvikvm(6088): threadid=17: thread exiting with uncaught exception (group=0x4001b180) 
04-08 11:56:20.467: ERROR/AndroidRuntime(6088): Uncaught handler: thread IntentService[UploadService] exiting due to uncaught exception 
04-08 11:56:20.467: ERROR/AndroidRuntime(6088): java.lang.OutOfMemoryError 
04-08 11:56:20.467: ERROR/AndroidRuntime(6088):  at java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java:93) 
04-08 11:56:20.467: ERROR/AndroidRuntime(6088):  at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:218) 
04-08 11:56:20.467: ERROR/AndroidRuntime(6088):  at com.android.election2010.UploadService.readBytes(UploadService.java:199) 
04-08 11:56:20.467: ERROR/AndroidRuntime(6088):  at com.android.election2010.UploadService.getBytesFromFile(UploadService.java:182) 
04-08 11:56:20.467: ERROR/AndroidRuntime(6088):  at com.android.election2010.UploadService.doUploadinBackground(UploadService.java:118) 
04-08 11:56:20.467: ERROR/AndroidRuntime(6088):  at com.android.election2010.UploadService.onHandleIntent(UploadService.java:85) 
04-08 11:56:20.467: ERROR/AndroidRuntime(6088):  at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:30) 
04-08 11:56:20.467: ERROR/AndroidRuntime(6088):  at android.os.Handler.dispatchMessage(Handler.java:99) 
04-08 11:56:20.467: ERROR/AndroidRuntime(6088):  at android.os.Looper.loop(Looper.java:123) 
04-08 11:56:20.467: ERROR/AndroidRuntime(6088):  at android.os.HandlerThread.run(HandlerThread.java:60) 
04-08 11:56:20.496: INFO/Process(4657): Sending signal. PID: 6088 SIG: 3 

Chyba że as @DroidIn suggests muszę przesłać go na kawałki. Ale (pytanie o newbie) czy to oznacza, że ​​powinienem wykonać wiele żądań PostMethod i skleić plik na końcu serwera? Czy mogę załadować bajtestream do pamięci w porcjach i skleić go razem w kodzie Android?

Gdyby ktoś mógł dać mi wskazówkę co do najlepszego podejścia, byłbym bardzo wdzięczny.

Odpowiedz

3

Nie musisz przenosić całego pliku do pamięci, a następnie przesłać go za jednym razem. Wywołaj połączenie.getOutputStream() i write() bajty w porcjach.

+0

Zasadniczo zamień ten "ByteArrayOutputStream" w readBytes() na "OutputStream" skojarzony z połączeniem. – wds

10

Jim Blackler ma absolutną rację. Nie możesz mieć pełnego wideo w pamięci w bajcie []. Tak więc powinieneś przeczytać plik nie na bajcie [], ale bezpośrednio na HttpUrlConnectio.getOutputStream().

Ale nawet po tym nadal otrzymasz OutOfMemory, ponieważ HttpUrlConnection buforuje wszystkie dane wyjściowe w pamięci i wysyła je do sieci dopiero po zakończeniu pisania.

Aby zmienić to zachowanie, można użyć HttpUrlConnection.setChunkedStreamingMode() lub HttpUrlConnection.setFixedLengthStreamingMode(). Jeśli twój serwer akceptuje fragmenty strumienia, możesz użyć setChunkedStreamingMode(). W przeciwnym razie będziesz musiał użyć setFixedLengthStreamingMode. Aby użyć setFixedLengthStreamingMode, musisz znać dokładną długość treści przed rozpoczęciem przesyłania strumieniowego danych, więc jest to trochę trudne.

Koniec z OutOfMemory w tym momencie.

Jeśli masz plik wideo w pliku, możesz wybrać inne podejście, o wiele prostsze. Użyj HttpClient i FileBody w ten sposób: How to send HTTP POST request and receive response?. Myślę, że implementują wszystkie powyższe metody i nie musisz się o to martwić.

+0

Dziękuję, @Fedor, jest to bardzo pomocne. – neevek

+0

Czy możesz zaproponować, który z nich jest najlepszy? W tej chwili robię R & D, tworząc porcje i przesyłając to samo po kolei. Czy to jest dobra droga? –

+0

@Fedor Skąd mam wiedzieć, czy mój serwer Apache akceptuje fragmenty strumienia? Wiem, że jeśli mam zestaw 'setChunkedStreamingMode()' nie otrzymuję żadnych danych: http://stackoverflow.com/q/15913844/317889 – HGPB

1

Tylko mała uwaga:

setChunkedStreamingMode i setFixedeLengthStreamingMode nie działają w Android 2.1, Działają one idealne w 2,0 i 2,2

+0

Miałem odwrotną sytuację: setChunkedStreamingMode działa w wersji 2.3.3 i nie działa w wersji 2.2. Wygląda na to, że powinniśmy użyć HttpClient dla v. <2.3 i HttpUrlConnection> 2.2 Podwójne kodowanie :( –

0

Jej lepiej podzielić plik na części i przesłać. Scal części po stronie serwera.

Powiązane problemy