Reputation: 38
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
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