Загрузка и загрузка изображений Android с помощью Base64 в JSON вызывает ошибку в памяти

В настоящее время я кодирую и декодирую изображения на Base64. Я преодолел исходную проблему с OOM с использованием потоков для кодирования изображений в строки.

Моя проблема в том, что я не могу понять, как добавить несколько закодированных строк Base64 для изображений с несколькими разрешениями (5620 x 3747 - 4.92MB или 3264 x 1836 - 1.35MB) в объект JSON через Gson. В настоящее время Gson выбрасывает исключение OOM только с 2 строками Base64 из изображения 5312 x 2988 - 4.95 МБ.

Я понимаю, что андроид может только сэкономить 16/20 Мб для каждого приложения, поэтому это преобразование должно быть намного выше предела.

Как написать строку Base64 в потоке для объекта JSON, который будет содержать конкретные значения, необходимые для публикации на моем сервере?

Было бы проще изменить мой сервер, чтобы принять запрос Multi-Part вместо POJO на основе JSON с несколькими Base64 Strings? В настоящее время я использую Volley, и нет официального запроса Multi-Part, а также потокового ввода-вывода.

Если это вопрос сжатия, сколько сжатий я должен применить к изображению перед кодированием в строку Base64? Я в идеале хочу потерять практически любое качество, но иметь оптимальные уровни сжатия.

Бит больше информации

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

Я понимаю, что некоторые изображения могут быть настолько большими, что их загрузка в память приведет к исключениям. Это то, что я попытаюсь обработать позже.

В некоторых случаях изображения, которые будут загружены, могут занимать от 1 до 200.

Я пытаюсь найти наиболее оптимальное решение, которое будет хорошо масштабироваться.

Ответ 1

Я рассмотрел использование Volley как механизма транспортировки больших объектов JSON на сервер и нашел этот ответ. Этот ответ по существу доказал, что Воллей будет плохой идеей для того, что я хотел.

Я переключился на OkHttp и теперь использует их потоковые методы, позволяющие передавать JSON на сервер, а затем читать ответ с помощью оптимизированный подход. Я использовал библиотеку GSON для анализа ответа, поскольку OKHttp позволяет передавать JSON/Object JSON/Object в объект-читатель, который затем использует Gson для внутренней потоковой передачи и разбора в класс POJO.

Единственная причина, по которой я не переключился на запрос Multi-Part, был из-за того, что реализация на стороне сервера была жесткой и неизменной для покрытия запросов Multi-Part, она строго ожидала представления данных и файлов JSON.

Для обработки изображений Base64 на Android я строго рекомендую не использовать представление String и просто конвертировать в Bytes, чтобы сэкономить на использовании чрезмерного объема памяти. Я прочитал эту статью об использовании и управлении памятью String. С помощью Bytes вы можете легко переносить данные, не оставляя массивной памяти в памяти.

Для отображения изображений я все же избегаю преобразования байтов в String с помощью библиотеки изображений Glide. Они позволяют вам пройти в byte[], который имел огромное удобство.

Ответ 2

... для изображений с несколькими разрешениями (5620 x 3747 - 4,92 МБ или 3264 x 1836 - 1,35 МБ)...

Не уверен, что это размер файла или память, необходимая для размещения изображения в памяти, но взглянув на следующую ссылку: http://www.scantips.com/basics1d.html, я вижу следующее:

Для изображения размером 4000 x 2500 пикселей

тогда: 4000 x 2500 пикселей = 4000x2500 = 10 мегапикселей

4000x2500 x 3 = 30 миллионов байт (если 24-разрядный RGB)

30 000 000 байт /(1024 x 1024) = 28,61 мегабайт (МБ)

Это просто, насколько велики данные - для ЛЮБОЙ 24-разрядной 10-мегапиксельной но JPG файлы сжимают его меньше (только в файле).

Я думаю, что изображения, которые вы обрабатываете, занимают гораздо больше памяти, чем вы ожидаете.

Кроме того, взглянув на этот вопрос и ответ: fooobar.com/info/94325/..., мы знаем, что представление base64 изображения занимает до 37% больше памяти, чем оригинальный размер изображения.

Как написать строку Base64 в потоке для объекта JSON, который будет содержать конкретные значения, необходимые для публикации на моем сервере?

Я думаю, вы могли бы сделать это (с небольшими изображениями не большими), просто добавив представление base64 изображения в объект JSON, а затем отправляя его на сервер.

Было бы проще изменить мой сервер, чтобы принять запрос Multi-Part вместо POJO на основе JSON с несколькими строками Base64?

На мой взгляд, это будет ваш лучший вариант для реализации того, что вы пытаетесь достичь.

В настоящее время я использую Volley, и нет официального запроса на несколько частей, а также потокового ввода-вывода.

Вы можете взглянуть на этот ответ: fooobar.com/info/70120/..., вы можете определенно сделать это с помощью залпа, но если вы хотите альтернативу, вы можете попробовать с модификацией (http://square.github.io/retrofit/), они поддерживают Multipart в нашем поле.

например:

@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);