What to Do on Transactiontoolargeexception

What to do on TransactionTooLargeException

I encountered this issue, and I found that when there huge amount of data getting exchanged between a service and an application,(This involves transferring lots of thumbnails). Actually data size was around 500kb, and the IPC transaction buffer size is set to 1024KB. I am not sure why it exceeded the transaction buffer.

This also can occur, when you pass lot of data through intent extras

When you get this exception in your application, please analyze your code.

  1. Are you exchanging lot of data between your services and application?
  2. Using intents to share huge data, (for example, the user selects huge number of files from gallery share press share, the URIs of the selected files will be transferred using intents)
  3. receiving bitmap files from service
  4. waiting for android to respond back with huge data (for example, getInstalledApplications() when the user installed lot of applications)
  5. using applyBatch() with lot of operations pending

How to handle when you get this exception

If possible, split the big operation in to small chunks, for example, instead of calling applyBatch() with 1000 operations, call it with 100 each.

Do not exchange huge data (>1MB) between services and application

I dont know how to do this, but, Do not query android, which can return huge data :-)

What to do on TransactionTooLargeException

I encountered this issue, and I found that when there huge amount of data getting exchanged between a service and an application,(This involves transferring lots of thumbnails). Actually data size was around 500kb, and the IPC transaction buffer size is set to 1024KB. I am not sure why it exceeded the transaction buffer.

This also can occur, when you pass lot of data through intent extras

When you get this exception in your application, please analyze your code.

  1. Are you exchanging lot of data between your services and application?
  2. Using intents to share huge data, (for example, the user selects huge number of files from gallery share press share, the URIs of the selected files will be transferred using intents)
  3. receiving bitmap files from service
  4. waiting for android to respond back with huge data (for example, getInstalledApplications() when the user installed lot of applications)
  5. using applyBatch() with lot of operations pending

How to handle when you get this exception

If possible, split the big operation in to small chunks, for example, instead of calling applyBatch() with 1000 operations, call it with 100 each.

Do not exchange huge data (>1MB) between services and application

I dont know how to do this, but, Do not query android, which can return huge data :-)

TransactionTooLargeException When Taking Photo

Fix

In short you need to reconsider saving images in the database and consider storing a path to the image (or suitable part thereof, to uniquely identify the image) with the actual image being store at a suitable location.

An alternative, but perhaps still quite costly resource wise. Could be to consider storing manageable chunks of images (perhaps consider 100k chunks).
e.g. How to use images in Android SQLite that are larger than the limitations of a CursorWindow?

Another alternative could be to store smaller images (if any consider they are photos) in the database but larger images as paths.
e.g. How can I insert image in a sqlite database

The Issue

What you have come across is a precursor (pun intended :)) to other problems with the size of images.

That is you have exceeded the 1Mb limit of a Parcel as explained by TransactionTooLargeException which includes :-

The Binder transaction buffer has a limited fixed size, currently 1MB, which is shared by all transactions in progress for the process. Consequently this exception can be thrown when there are many transactions in progress even when most of the individual transactions are of moderate size.

Your parcel(image) appears to be 14763232 i.e. 14Mb.

Even if you increased the parcel Size you could then hit the Android SQLite implementation and therefore Room issues with Cursor size limitations and or the inefficiencies of the reduced number of rows in a Cursor.

When creating a new row or taking a photo in a row which has no picture, I'm able to take the photo and save it into my database without any problem.

When inserting the limitations aren't there as you insert on an individual basis. The limitations are when extracting the data as typically/often groups of data are extracted in a single request and an intermediate buffer is used (i.e. a Cursor is a buffer).

TransactionTooLargeException even when file size is super small

So what it ultimately took resolve this TransactionTooLarge Exception, was to identify the Activity that had its subordinate fragments, views etc adding data parcels to the bundle. Then I ran this code in said Activity:

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//Clear the Activity's bundle of the subsidiary fragments' bundles.
outState.clear();
}

That fixed it for me. Hope this help someone out there!

TransactionTooLargeException in Nougat

Your are passing too much data to your Fragment in setArguments(). Your Fragment will work, but when it tries to save its instance state it overflows the transaction buffer. This throws a RuntimeException if you target Android 7.0 (API 24 or higher). To preserve backwards compatibility and not break existing apps, the new behaviour is only used if you target API 24 or higher. If you target API < 24, the transaction buffer overflow exception is caught and silently ignored. This means that your data will not be persistently saved, which you may (or may not) notice.

Your code is broken. You should not pass large amounts of data to the Fragment in setArguments(). You can keep your data in your Activity. When the Fragment wants to access the data, it can always so something like this:

// Get the owning Activity
MyActivity activity = (MyActivity)getActivity();
// Get the data from the Activity
List<Data> data = activity.getData();

In your Activity, write a getData() method that returns a reference to whatever data the Fragment needs.

In this way, the data is held in the Activity and the Fragment can get access to it whenever it needs to.

android.os.TransactionTooLargeException on Nougat

In the end, my problem was with things that were being saved onSaveInstance, and not with things that were being sent to the next activity. I removed all saves where I can't control the size of objects (network responses), and now it's working.

Update 2:

Google now provides AndroidX ViewModel which is based on the same technology as retained Fragments but much easier to use. Now ViewModel is a preferred approach.

Update 1:

To preserve big chunks of data, Google is suggesting to do it with Fragment that retains instance. Idea is to create an empty Fragment without a view with all necessary fields, that would otherwise be saved in the Bundle. Add setRetainInstance(true); to Fragment's onCreate method.
And then save data in Fragment on Activity's onDestroy and load them onCreate.
Here is an example of Activity:

public class MyActivity extends Activity {

private DataFragment dataFragment;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

// find the retained fragment on activity restarts
FragmentManager fm = getFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(“data”);

// create the fragment and data the first time
if (dataFragment == null) {
// add the fragment
dataFragment = new DataFragment();
fm.beginTransaction().add(dataFragment, “data”).commit();
// load the data from the web
dataFragment.setData(loadMyData());
}

// the data is available in dataFragment.getData()
...
}

@Override
public void onDestroy() {
super.onDestroy();
// store the data in the fragment
dataFragment.setData(collectMyLoadedData());
}
}

An example of Fragment:

public class DataFragment extends Fragment {

// data object we want to retain
private MyDataObject data;

// this method is only called once for this fragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retain this fragment
setRetainInstance(true);
}

public void setData(MyDataObject data) {
this.data = data;
}

public MyDataObject getData() {
return data;
}
}

More about it, you can read here.



Related Topics



Leave a reply



Submit