Android: OutOfMemoryError при загрузке видео - как лучше разделить на части? - PullRequest
6 голосов
/ 08 апреля 2010

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

Вот мой код:

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

И вотtraceback (ошибка выдается в строке 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

Я думаю, что , как @DroidIn предлагает , мне нужно загрузить его порциями.Но (предупреждение о новичке) означает ли это, что я должен сделать несколько запросов PostMethod и склеить файл вместе на стороне сервера?Или я могу загрузить байтовый поток в память кусками и склеить его вместе в коде Android?

Если бы кто-нибудь мог дать мне подсказку относительно наилучшего подхода, я был бы очень благодарен.

Ответы [ 4 ]

11 голосов
/ 08 июля 2010

Джим Блэклер абсолютно прав. Вы не можете иметь полное видео в памяти в байтах []. Поэтому вы должны читать файл не в byte [], а непосредственно в HttpUrlConnectio.getOutputStream ().

Но даже после этого вы все равно получите OutOfMemory, поскольку HttpUrlConnection кэширует все выходные данные в памяти и отправляет их в сеть только после завершения записи.

Чтобы переопределить это поведение, вы можете использовать HttpUrlConnection.setChunkedStreamingMode () или HttpUrlConnection.setFixedLengthStreamingMode (). Если ваш сервер принимает потоковые чанки, вы можете использовать setChunkedStreamingMode (). В противном случае вам придется использовать setFixedLengthStreamingMode. Чтобы использовать setFixedLengthStreamingMode, вам нужно знать точную длину содержимого перед началом потоковой передачи данных, так что это немного сложно.

Больше нет OutOfMemory.

Если у вас есть видео в файле, вы можете выбрать другой подход, гораздо более простой. Используйте HttpClient и FileBody вот так Как отправить HTTP-запрос POST и получить ответ? . Я думаю, что они реализуют все описанные выше методы, и вам не придется об этом беспокоиться.

3 голосов
/ 09 апреля 2010

Вам не нужно хранить весь файл в памяти, а затем загружать его за один раз. Вызовите connection.getOutputStream () и write () байтов в чанках.

2 голосов
/ 20 сентября 2010

Просто небольшая заметка:

setChunkedStreamingMode и setFixedeLengthStreamingMode НЕ работают в Android 2.1, они отлично работают в 2.0 и 2.2

0 голосов
/ 30 июня 2011

Лучше разбить файл на части и загрузить.Объединить части на стороне сервера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...