AndroidRuntime: FATAL EXCEPTION, java .lang.OutOfMemoryError при отправке нескольких изображений - PullRequest
0 голосов
/ 20 января 2020

Я пытаюсь отправить много изображений на API, используя okHttp3 и retrofit2. Я попытался отправить изображения с одного устройства (5 изображений одновременно), и это работало хорошо. Затем я попытался отправить 5 изображений с 5 устройств одновременно, и это работало хорошо, но когда я попытался отправить 30 изображений с 5 устройств, я получил следующую ошибку:

    2020-01-17 14:57:07.416 32244-32264/my.example.com.puri W/zygote: Throwing OutOfMemoryError "Failed to allocate a 102554120 byte allocation with 8388608 free bytes and 97MB until OOM, max allowed footprint 174912000, growth limit 268435456"
2020-01-17 14:57:07.422 32244-32264/my.example.com.puri E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
    Process: my.example.com.puri, PID: 32244
    java.lang.OutOfMemoryError: Failed to allocate a 102554120 byte allocation with 8388608 free bytes and 97MB until OOM, max allowed footprint 174912000, growth limit 268435456
        at java.lang.StringFactory.newStringFromBytes(StringFactory.java:178)
        at java.lang.StringFactory.newStringFromBytes(StringFactory.java:209)
        at okio.Buffer.readString(Buffer.java:620)
        at okio.Buffer.readString(Buffer.java:603)
        at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:198)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:185)
        at okhttp3.RealCall$AsyncCall.execute(RealCall.java:135)
        at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)

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

Я также внес эти изменения в Manifest.

<application
    android:hardwareAccelerated="false"
    android:largeHeap="true"
>

И вот как я делаю запрос.

@Multipart
@POST("installationdocument")
Call<Void> createNewDocument(@Header(AUTH_HEADER) String authorization, @Part ArrayList<MultipartBody.Part> images, @Part("document") RequestBody json);

И:

@Override
public void callRestApi(PuriRestApi restApi, RestApiJobService.ApiRequestor apiRequestor) {
    MediaType JSON = MediaType.parse("application/json");
    MediaType JPG = MediaType.parse("image/jpg");

    ArrayList<MultipartBody.Part> imageParts = new ArrayList<>();
        for (String imagePath : imagePaths) {
            File image = new File(imagePath);
            RequestBody imageBody = RequestBody.create(JPG, image);
            imageParts.add(MultipartBody.Part.createFormData("images", image.getName(), imageBody));
        }
    RequestBody jsonPart = RequestBody.create(JSON, documentString);

    apiRequestor.request(restApi.createNewDocument(authentication, imageParts, jsonPart), response -> {
        if (response.isSuccessful()) {
            if (imagePaths != null && imagePaths.length > 0) {
                for (String imagePath : imagePaths) {
                    File image = new File(imagePath);
                    image.delete();
                }
            }
            return true;
        } else {
            return false;
        }
    });
}

Возможно, создание большой переменной - это то, что вызывает эту ошибку. Поскольку переменная ArrayList<MultipartBody.Part> imageParts будет содержать около 150 МБ данных изображения с 30 изображениями. Но кроме этого я понятия не имею, что может быть причиной этой ошибки.

Любая помощь действительно приветствуется.

Ответы [ 3 ]

2 голосов
/ 20 января 2020

Если я не прочитал этот стек ошибок, мне кажется, что эта ошибка происходит из-за того, что HttpLoggingInterceptor пытается выделить буфер размером 102 МБ, чтобы в буквальном смысле записать в журнал все данные вашего изображения.

Если это так, я полагаю, что вы для уровня ведения журнала установлено значение BODY, и в этом случае установка любого другого уровня устранит проблему.

0 голосов
/ 20 января 2020

Вы можете использовать метод сжатия перед отправкой изображений на сервер

public  Bitmap compressInputImage(Uri inputImageData){
try {
bitmapInputImage=MediaStore.Images.Media.getBitmap(context.getContentResolver(),     inputImageData); 

        if (bitmapInputImage.getWidth() > 2048 && bitmapInputImage.getHeight() > 2048)
        {
            dpBitmap = Bitmap.createScaledBitmap(bitmapInputImage, 1024, 1280, true);            }
        else if (bitmapInputImage.getWidth() > 2048 && bitmapInputImage.getHeight() < 2048)
        {
            dpBitmap = Bitmap.createScaledBitmap(bitmapInputImage, 1920, 1200, true);            }
        else if (bitmapInputImage.getWidth() < 2048 && bitmapInputImage.getHeight() > 2048)
        {
            dpBitmap = Bitmap.createScaledBitmap(bitmapInputImage, 1024, 1280, true);            }
        else if (bitmapInputImage.getWidth() < 2048 && bitmapInputImage.getHeight() < 2048)
        {
            dpBitmap = Bitmap.createScaledBitmap(bitmapInputImage, bitmapInputImage.getWidth(), bitmapInputImage.getHeight(), true);            }
    } catch (Exception e)
    {
        dpBitmap = bitmapInputImage;

    }
    return dpBitmap;
}

Это может минимизировать шансы OutOfMemory Exception. Помимо этого вы можете обработать исключение, добавив try - catch.

0 голосов
/ 20 января 2020

Добавьте нижеприведенные объекты в файл манифеста android: hardwareAccelerated = "false", android: largeHeap = "true", это будет работать для некоторых сред.

<application
android:allowBackup="true"
android:hardwareAccelerated="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">

См. Ответ StackOverflow для деталей ...

...