Passing large data to an activity

photo by The Consumerist (http://www.flickr.com/photos/consumerist/)
The issue with arguments…
Recently I have encountered a problem while passing a large data to an activity. There was a need to pass around 10 megabytes of data in an object array from one activity to another, and while trying to do that the second activity would not start at all and in my case (app’s min version 4.0) Android would not give me any clue (exception) of an issue. As soon as I realized what the problem was I started looking into solutions.
There are several ways to post data to an activity, and the recommended (official, by Google) one is using Intents with extras. Here is a usual way to achieve this:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
package com.jyvee.arguments; import java.util.ArrayList; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Parcelable; public class SomeActivity extends Activity { // Names for the arguments we pass to the // activity when we create it private final static String ARG_STRING = "ARG_STRING"; private final static String ARG_INT = "ARG_INT"; private final static String ARG_LIST = "ARG_LIST"; private String stringField; private int intField; private ArrayList<Parcelable> arrayField; @Override protected void onCreate(final Bundle savedState) { super.onCreate(savedState); // Get the activity intent if there is a one final Intent intent = getIntent(); // And retrieve arguments if there are any if (intent.hasExtra(ARG_STRING)) { stringField = intent.getExtras().getString(ARG_STRING); } if (intent.hasExtra(ARG_INT)) { intField = intent.getExtras().getInt(ARG_INT); } if (intent.hasExtra(ARG_LIST)) { arrayField = intent.getExtras().getParcelableArrayList(ARG_LIST); } // Now stringField, intField fields are available // within the class and can be accessed directly } /** * /** A static method for starting activity with supplied arguments * * @param contextA * context that starts this activity * @param stringArg * A string argument to pass to the new activity * @param intArg * An int argument to pass to the new activity * @param objectList * An object list argument to pass to the new activity */ public static void startActivity(final Context context, final String stringArg, final int intArg, final ArrayList<? extends Parcelable> objectList) { // Initialize a new intent final Intent intent = new Intent(context, SomeActivity.class); // To speed things up :) intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); // And add arguments to the Intent intent.putExtra(ARG_STRING, stringArg); intent.putExtra(ARG_INT, intArg); intent.putParcelableArrayListExtra(ARG_LIST, objectList); context.startActivity(intent); } } |
For many occasions using Intent extras is the best way to submit data from one activity to another. The problem comes when you try to pass large data to an activity (more than 1 MB). There was no such need in early Android versions since the actual devices had very limited RAM (heap memory). Newer devices are bundled with much larger RAM and since sending objects directly (via a reference, as opposed to persisting data in first activity and retrieving it in a second one) is the fastest way to pass large data to an activity I decided to do a research and find a way around the issue.
So, how do we pass large data to an activity?
There are several suggestions to achieve this, through defining global variables, static fields, member variables, etc. Having tweaked those ones a bit to get clean encapsulated code, I decided to implement it using Java enum. Here is the code:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
package com.jyvee.arguments; import java.util.List; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; public class SomeActivity extends Activity { // Names for the arguments we pass to the // activity when we create it private final static String ARG_STRING = "ARG_STRING"; private final static String ARG_INT = "ARG_INT"; private String stringField; private int intField; private List<Object> arrayField; private enum DataHolder { INSTANCE; private List<Object> mObjectList; public static boolean hasData() { return INSTANCE.mObjectList != null; } public static void setData(final List<Object> objectList) { INSTANCE.mObjectList = objectList; } public static List<Object> getData() { final List<Object> retList = INSTANCE.mObjectList; INSTANCE.mObjectList = null; return retList; } } @Override protected void onCreate(final Bundle savedState) { super.onCreate(savedState); // Get the activity intent if there is a one final Intent intent = getIntent(); // And retrieve arguments if there are any if (intent.hasExtra(ARG_STRING)) { stringField = intent.getExtras().getString(ARG_STRING); } if (intent.hasExtra(ARG_INT)) { intField = intent.getExtras().getInt(ARG_INT); } // And we retrieve large data from enum if (DataHolder.hasData()) { arrayField = DataHolder.getData(); } // Now stringField, intField fields are available // within the class and can be accessed directly } /** * /** A static method for starting activity with supplied arguments * * @param contextA * context that starts this activity * @param stringArg * A string argument to pass to the new activity * @param intArg * An int argument to pass to the new activity * @param objectList * An object list argument to pass to the new activity */ public static void startActivity(final Context context, final String stringArg, final int intArg, final List<Object> objectList) { // Initialize a new intent final Intent intent = new Intent(context, SomeActivity.class); // To speed things up :) intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); // And add arguments to the Intent intent.putExtra(ARG_STRING, stringArg); intent.putExtra(ARG_INT, intArg); // Now we put the large data into our enum instead of using Intent extras DataHolder.setData(objectList); context.startActivity(intent); } } |



