jsp phani
jsp phani

Reputation: 38

How to deal with OutOfMemoryError in Android

Server sends images in the form of byte arrays to my android application. In a loop, Each received byte array is converted to bitmap to be displayed in a ImageView. Problem is that my android device(vince) gives OutOfMemoryError after sometime(like 2-3 minutes). This is the same case with emulators too. Is there a way i can avoid this error ? Also, I've set largeHeap to true

Log :

2020-03-31 20:39:28.040 30083-30158/com.rollout.pcremoteclient E/AndroidRuntime: FATAL EXCEPTION: Thread-2
    Process: com.rollout.pcremoteclient, PID: 30083
    java.lang.OutOfMemoryError: Failed to allocate a 153632 byte allocation with 105792 free bytes and 103KB until OOM, target footprint 536870912, growth limit 536870912
        at java.lang.reflect.Array.newArray(Array.java:782)
        at java.lang.reflect.Array.newInstance(Array.java:78)
        at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1769)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1406)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
        at com.rollout.pcremoteclient.MainActivity$1.run(MainActivity.java:30)

MainActivity.java :

package com.rollout.pcremoteclient;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;

import java.io.ObjectInputStream;
import java.net.Socket;
import java.util.logging.SocketHandler;

public class MainActivity extends AppCompatActivity {

    ImageView imageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        Thread thread = new Thread(){
            @Override
            public void run(){
                try {
                    Socket socket = new Socket("192.168.43.191",6777);
                    ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
                    while (true) {
                        final byte[] image_bytearr = (byte[])objectInputStream.readObject();
                        BitmapFactory.Options options = new BitmapFactory.Options();
                        options.inMutable = true;
                        final Bitmap bmp = BitmapFactory.decodeByteArray(image_bytearr, 0, image_bytearr.length, options);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                imageView.setImageBitmap(bmp);
                            }
                        });
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        };
        thread.start();
    }
    public void init(){
        imageView = (ImageView) findViewById(R.id.imageView);
    }
}

ServerSide :

robot = new Robot();
rectangle = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
while (true) {
    BufferedImage bufferedImage = robot.createScreenCapture(rectangle);
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    ImageIO.write(bufferedImage, "jpg", byteArrayOutputStream);
    byte[] image_byte_arr = byteArrayOutputStream.toByteArray();
    objectOutputStream.writeObject(image_byte_arr);
    }

Upvotes: 0

Views: 298

Answers (1)

Rendón
Rendón

Reputation: 300

The best thing you can do is decrease the image in the server side, because android have a limit of memory ram that can give per application, no matter is your device have 9gb of RAM for example the operating system give you the max amount depending of the device screen resolution.

But in order to decrease locally your memory usage (but you can still get a OutOfMemoryError) is compress the local image after parse and also convert these image to a Webp format to reduce even more the final size of the image, the problem with these is the time to process the image

Conver to Webp (Google image Format) and compress

Bitmap bitmap;
String fileUrl;

//Get your file URL
//fileUrl
bitmap = BitmapFactory.decodeStream(fileUrl, null, null);
FileOutputStream out = this.openFileOutput(Utils.getFilenameFromUrl(Utils.getFilenameFromUrl(preview)), Context.MODE_PRIVATE);
bitmap.compress(Bitmap.CompressFormat.WEBP, 50, out);

Also in your AndroidManifest.xml turn on the Large Heap usage adding android:largeHeap="true" to your <application> tag

Upvotes: 1

Related Questions