3

I just started a new job and am working on an app that requires passing large data sets around the application. Currently the app uses persistent storage and is constantly querying a SQL database to fetch and display these large data sets to the user. Because of all of these expensive operations the app has become almost unusable (too many loading spinners for operations that take too long). My solution is to load the data when the main activity is launched and then pass it as needed to any new activities.

I implemented the first stage of this change with one data set. However, when I tried to pass the ArrayList with all this data in the intent's extras bundle I got the following error:

04-27 06:42:32.022: E/AndroidRuntime(14180): FATAL EXCEPTION: main
04-27 06:42:32.022: E/AndroidRuntime(14180): Process: com.myprocess, PID: 14180
04-27 06:42:32.022: E/AndroidRuntime(14180): java.lang.SecurityException: Unable to find app for caller android.app.ApplicationThreadProxy@42b32678 (pid=14180) when publishing content providers
04-27 06:42:32.022: E/AndroidRuntime(14180):    at android.os.Parcel.readException(Parcel.java:1472)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at android.os.Parcel.readException(Parcel.java:1426)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at android.app.ActivityManagerProxy.publishContentProviders(ActivityManagerNative.java:2977)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at android.app.ActivityThread.installContentProviders(ActivityThread.java:4591)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4522)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at android.app.ActivityThread.access$1500(ActivityThread.java:151)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1381)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at android.os.Handler.dispatchMessage(Handler.java:110)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at android.os.Looper.loop(Looper.java:193)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at android.app.ActivityThread.main(ActivityThread.java:5292)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at java.lang.reflect.Method.invokeNative(Native Method)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at java.lang.reflect.Method.invoke(Method.java:515)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
04-27 06:42:32.022: E/AndroidRuntime(14180):    at dalvik.system.NativeStart.main(Native Method)

Which, based on this stackoverflow post: Using Crop intent Getting java.lang.SecurityException: Unable to find app for caller android.app.ApplicationThreadProxy@4266ae80 as well as testing with smaller data-sets I figured out was (almost certainly) being caused by sending too much data via the intent extras bundle.

I have two questions.

  1. First, does my assessment sound correct? I haven't been able to find anything from the last four years that explicitly states that the extras bundle has a size limit (there's lots from 2012 and before though).
  2. Assuming I'm correct, I'm planning on using a singleton to store data sets that are too big to be passed as an intent, and then implementing the necessary checks to ensure that it works with the activity life cycle (re-load the from the database if the activity is destroyed and I loose the data). Any other suggestions? I know this isn't exactly best practice but I can't think of a better way to do it.

I should also mention that because of the usability requirements for the app loading the data incrementally isn't an option.

Community
  • 1
  • 1
Sam Wilks
  • 67
  • 2
  • 10
  • Your log could mean, that there is already ContentProvider with such name, and you cannot register one more, or there is something with your provider. Although, it could be some missing permissions for access content – Petrov Dmitrii Apr 28 '16 at 08:43
  • ArrayList passing needs parcel able implementation – Haroon Apr 28 '16 at 08:44
  • The only code I added was to load the data from the database using a AsyncTaskLoader in the first activity and then pass that data to a second activity in an intent. I'm definitely not doing anything with content providers. My guess is that the log is referring to the one that the Android system uses to launch an activity with an intent with data in it. – Sam Wilks Apr 28 '16 at 08:49
  • And yes, all data I'm passing in my array is Parcelable - that's definitely not my problem. – Sam Wilks Apr 28 '16 at 08:50

1 Answers1

6

Yes there is a limit, but it's not well documented how large or small it is.

See: Max size of string data that can be passed in intents

Some say you shouldn't try to pass anything larger than 90kb into the Intent extras. So the limit seems to be quite tight.

Your options:

  • Store the data in any easy to read temporary file and pass a file pointer to that file around.
  • Store the data in the Application instance of your app, not as a singleton but something accessible through (MyAppInstance) context.getApplicationContext().

Example of the last option:

Note: you might want to synchronize access to the data.

public class MyAppInstance extends Application {
    private Object data = null;

    public void setMyData(Object data){
        this.data = data;
    }

    public Object getMyData(){
        return data;
    }

}

MyAppInstance app = (MyAppInstance) context.getApplicationContext();

app.setMyData(whatever);
whatever = app.getMyData();
Community
  • 1
  • 1
Rolf ツ
  • 8,611
  • 6
  • 47
  • 72
  • 1
    Yea, I'm weary of using the application instance (this blog post is a good explanation of why http://www.developerphil.com/dont-store-data-in-the-application-object/), but that said it's probably safer than using a singleton. – Sam Wilks Apr 28 '16 at 08:54
  • The problem described in the blog post is a common pit fall but the same problem can also occur when using a singleton. That being said, an application instance is probably your best chance, if proper used. – Rolf ツ Apr 28 '16 at 08:57