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.
- Are you exchanging lot of data between your services and application?
- 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)
- receiving bitmap files from service
- waiting for android to respond back with huge data (for example, getInstalledApplications() when the user installed lot of applications)
- 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.
- Are you exchanging lot of data between your services and application?
- 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)
- receiving bitmap files from service
- waiting for android to respond back with huge data (for example, getInstalledApplications() when the user installed lot of applications)
- 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
Changing API Level Android Studio
Android Imageview Zoom-In and Zoom-Out
How to Display Count of Notifications in App Launcher Icon
How to Restart Activity in Android
How to Send Post Request in Json Using Httpclient in Android
Null Pointer Exception - Findviewbyid()
How to Load an Imageview by Url in Android
Android "Only the Original Thread That Created a View Hierarchy Can Touch Its Views."
Fling Gesture Detection on Grid Layout
How to Access My Localhost from My Android Device
Navigationview Get/Find Header Layout
How to Send a Json Object Over Request With Android
Notification Bar Icon Turns White in Android 5 Lollipop
How to Retrieve the Dimensions of a View
Difference Between Getcontext() , Getapplicationcontext() , Getbasecontext() and "This"
Get/Pick an Image from Android'S Built-In Gallery App Programmatically