For some reason occasionally when my Vehicle object is passed as a parcelable to another activity it breaches the maximum size:
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 569848 bytes
However the strange thing is this does not happen everytime. In my app I have an image and when I click it then it passes it to another activity. After multiple times of clicking this same image eventually it results in that exception. I am compressing the Bitmap as well. Does anyone know the issue?
I should also note if I compress with 30 I also have the same issue
package com.example.daniel.carbudgy.misc;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import com.example.daniel.carbudgy.R;
import com.example.daniel.carbudgy.tasks.ImageDownloaderCallback;
import com.example.daniel.carbudgy.tasks.ImageDownloaderTask;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.net.URL;
/**
* Created by daniel on 11/09/17.
*/
public class Vehicle implements Parcelable {
public interface VehicleHandler {
public void ready();
}
private int id;
private String name;
private String colour;
private String imageSrc;
private Drawable image;
private VehicleHandler handler;
public Vehicle(Parcel in) {
this.id = in.readInt();
this.name = in.readString();
this.colour = in.readString();
this.imageSrc = in.readString();
int length = in.readInt();
byte[] buf = new byte[length];
in.readByteArray(buf);
// Convert Bitmap to Drawable:
image = new BitmapDrawable(BitmapFactory.decodeByteArray(buf, 0, length));
}
public Vehicle(JSONObject vehicle_json) throws JSONException {
JSONObject manufacture = vehicle_json.getJSONObject("manufactureModel").getJSONObject("manufacture");
JSONObject model = vehicle_json.getJSONObject("manufactureModel").getJSONObject("model");
String vehicle_name = manufacture.getString("manufacture") + " " + model.getString("model");
Integer vehicle_id = vehicle_json.getInt("vehicleId");
String image_src = vehicle_json.getJSONObject("imageUpload").getString("url");
String colour = vehicle_json.getJSONObject("colour").getString("colour");
setId(vehicle_id);
setName(vehicle_name);
setColour(colour);
setImageSrc(image_src);
image = null;
handler = null;
}
public static final Creator<Vehicle> CREATOR = new Creator<Vehicle>() {
@Override
public Vehicle createFromParcel(Parcel in) {
return new Vehicle(in);
}
@Override
public Vehicle[] newArray(int size) {
return new Vehicle[size];
}
};
public void setHandler(VehicleHandler handler) {
this.handler = handler;
}
public void load() {
try {
URL url = new URL(imageSrc);
new ImageDownloaderTask(new ImageDownloaderCallback() {
@Override
public void success(Drawable[] drawables) {
image = drawables[0];
handler.ready();
}
@Override
public void fail() {
}
}).execute(url);
} catch(Exception ex) {
throw new RuntimeException(ex);
}
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColour() {
return colour;
}
public void setColour(String colour) {
this.colour = colour;
}
public String getImageSrc() {
return imageSrc;
}
public void setImageSrc(String imageSrc) {
this.imageSrc = imageSrc;
}
public Drawable getImage() {
return image;
}
public void setImage(Drawable image) {
this.image = image;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(getId());
parcel.writeString(getName());
parcel.writeString(getColour());
parcel.writeString(getImageSrc());
ByteArrayOutputStream out = new ByteArrayOutputStream();
((BitmapDrawable)getImage()).getBitmap().compress(Bitmap.CompressFormat.PNG, 0, out);
parcel.writeInt(out.size());
parcel.writeByteArray(out.toByteArray());
}
}
Does anyone know the issue?
Do not pass a Bitmap
in Intent
extras, in the saved instance state Bundle
, etc. Instead, pass information that allows the other party to use the bitmap:
By pulling it from some bitmap cache in your process
By loading the bitmap from its original source again (e.g., an https
URL)
There is a 1MB limit on Binder-based IPC transactions. That limit is on all outstanding transactions, and so multiple simultaneous transactions' combined memory usage needs to be below 1MB. As a result, the variance that you are seeing can be from:
Varying memory footprints from the Bitmap
itself, based on resolution, or
Varying other IPC transactions that are going on at the time
Your objective is to ensure that any such transaction — passing an Intent
outside of your process, for example — should be nowhere near that 1MB limit, so even if there are a few transactions going on at once, the combined total does not reach 1MB.