The Intent extras size limit

by Rolf Smit | 29 April 2016 | 05 May 2016 |
AndroidIntentTest

Today I'm starting something new, something I wanted to do for a long time, write blog posts about interesting things I encounter as developer. I really hope my blog posts will eventually inspire and help many other developers. This first blog posts is about something Android developers are quite familiar with, Intents.

An Intent in Android is sort of the connecting fiber between al kinds of components within the Android infrastructure. Intents usually describe a specific operation in an abstract way. Intents can be used to start Activities or Services but can also be used to broadcast specific operations. Most Android developers use them a lot.

Starting a new Activity is probably the most famous use-case. It's also very common to provide some extra arguments to the Activity, like the database row id in the example below.

Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("id", rowId);
startActivity(intent);

Size limit?

Intents may contain extra arguments (or extended data as the developer reference calls it). Extra arguments can be added to an Intent using the putExtra methods. Intents have to be serializable because they are not bound to the current app process. In Android this serialization is carried out by a specific API designed for high-performance. It boils down to this: only primitive types or objects which implement the android.os.Parcelable interface can be serialized. The official Android documentation doesn't say how much data you can add to an Intent, but it makes sense that there has to be a limit.

No supersizes here, it seems that there is a limit actually. As the author of the following Stackoverflow post found out the hard way: http://stackoverflow.com/questions/12496700/maximum-length-of-intent-putextra-method-force-close

Apparently if you try to put an enormous amount of data in an Intent your app will crash, I recreated this scenario with the following code:

Intent intent = new Intent(this, ActivityB.class);
intent.putExtra("bytes", new byte[1000 * 1000]);
startActivity(intent);

The Exception on Android 6 (API 23) is quite informative:

android.os.TransactionTooLargeException: data parcel size 1002388 bytes

On other (older) Android versions you are left with all kinds of different Exceptions, like:

java.lang.SecurityException: Unable to find app for caller... when publishing content providers
java.io.IOException: Address already in use

Testing

If you search the internet for the exact size limit (in bytes) of data that can be added to an Intent, you will find different statements ranging from 90Kb up to 1Mb but what is the exact limit? I decided to take the test and find the limit myself. I did a binary search to find the maximum amount of bytes that didn't cause a TransactionTooLargeException or some other exception.

Results

  • API 23: 517716 bytes (520107 bytes incl. overhead);
  • API 22: 517876 bytes;
  • API 19: 518368 bytes;
  • API 16: 518396 bytes;
  • API 10: 518580 bytes;

Testing has been done on multiple devices. All devices (inc. virtual and physical devices) reported the same results.

Overhead
The above results don't necessary mean that you can actually put that amount of bytes in an Intent as extra data, because there is of course some overhead as the Intent itself and the extra keys also have to be serialized by the Android system.

In my tests the overhead was 2391 bytes (on Android 6, API 23). The overhead might vary depending on at least the following things:

  • The full Java name of the Activity you're trying to start;
  • The String length of the key(s) you're using;
  • The length of target package name;
  • Intent action;
  • Intent type (Explicit or Implicit);
  • Android version;

Conclusion

The statements that Intents could transfer up to 1Mb worth of data are definitely wrong, 500Kb is more accurate. It also seems that the maximum amount decreases slightly per Android version, this has probably something to do with the addition of new features to the Intent or derived classes. My advice is to only add very basic arguments to an Intent, if you need to transfer more, you are left with the following options:

  • Store the data in a (temporary) file and pass around the file URI. This option is probably your only option if you want to transfer large amounts of data to a completely different app.
  • Store the data in the Application instance;
  • Create a singleton container holding the data you pass around.

Note: always check for null pointers
The last two options have a downside: If Android kills your app and thus the Activity stack you lose the data stored in both the singleton containers (the VM is killed) and the Application instance. If Android later restarts the Activities your app was displaying you might expect your singleton data to exist but it actually doesn't. So you must check if you data exists, don't assume it does.