Note: The title of this was changed to better reflect the actual problem.
I’ve run into a tricky nullPointerException – hoping someone here can give me an idea as to what is going wrong, as I am not successful in recreating the error so that I can get a debug stack trace.
The stack traces in the developer dashboard all indicate that the app is throwing a NullPointerException in onCreate from an Activity subclass (e.g., I have AActivity and BActivity both inheriting from BaseActivity which throws the exception). Presumably this is happening when the app is being resumed after having been thrown out of memory – at least that is my best guess. Although one user reports getting this error immediately on launching the app.
The onCreate function looks as follows:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.camp_ = MyApplication.getInstance().camp();
if (this.camp_ == null) {
this.finish();
return;
}
if (!this.camp_.isSane()) {
this.finish();
return;
}
}
That’s essentially it. MyApplication is the Application for the app; getInstance returns a pointer to the instance, or throws an IllegalStateException if the instance is null. isSane() essentially checks whether some of the variables in this.camp_ are null and returns false if the latter is the case.
I can’t for the life of me see how this can throw a NullPointerException, but… it apparently does. It’s my most frequent cause of error reports at the moment – but I’ve so far not had any luck provoking the issue myself (a problem I’ve frequently had with these bugs that only occur when the app restarts after having been wiped from memory).
[Edit 1]
Example stack trace:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.michael.android.app/com.michael.android.app.gui.GreetActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
at android.app.ActivityThread.access$2300(ActivityThread.java:125)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4627)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.michael.android.app.gui.BaseActivity.onCreate(Unknown Source)
at com.michael.android.app.gui.GreetActivity.onCreate(Unknown Source)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
... 11 more
As mentioned BaseActivity is inherited, so there are several variants of this same basic pattern of stack trace. onResume essentially does the same check for validity of the this.camp_ object – there is no onDestroy or onPause code in BaseActivity.
[Edit 2]
The getInstance code looks as follows:
public static MyApplication getInstance() {
checkInstance();
return instance_;
}
private static void checkInstance() {
if (instance_ == null)
throw new IllegalStateException("MyApplication not created yet!");
}
If instance was null, it should be returning an IllegalStateException, not a NPE.
Not really sure this is relevant, but here’s a snip of the Application class.
[Edit 3]
public class MyApplication extends Application {
// Instance
private static MyApplication instance_ = null;
private Camp camp_ = null;
public static MyApplication getInstance() {
checkInstance();
return instance_;
}
private static void checkInstance() {
if (instance_ == null)
throw new IllegalStateException("MyApplication not created yet!");
}
// Campaign
public Camp camp() {
return this.camp_;
}
private void parseSettings() {
if (getFileStreamPath("settings.xml").exists()) {
InputStream istream = null;
try {
istream = openFileInput("settings.xml");
/* Get a SAXParser from the SAXPArserFactory. */
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
/* Get the XMLReader of the SAXParser we created. */
XMLReader xr = sp.getXMLReader();
/* Create a new ContentHandler and apply it to the XML-Reader */
SettingsHandler handler = new SettingsHandler();
xr.setContentHandler(handler);
xr.parse(new InputSource(istream));
} catch (FileNotFoundException e) {
Log.e("MyApplication", "File not found exception: settings.xml");
} catch (Exception e) {
Log.e("MyApplication", "Exception thrown when decoding file settings.xml");
e.printStackTrace();
}
}
}
public void saveSettings() {
// ...
}
@Override
public void onCreate() {
super.onCreate();
// Set the instance
instance_ = this;
BaseActivity.flurryId = flurryId;
parseSettings();
}
public void setCamp(Camp c) {
this.camp_ = c;
}
}
I’m wondering if the issue may be something with the this reference being somehow incorrect in the onCreate methods.
Note that I had a BaseActivity (which is where the NPE occurs), which would be inherited by AActivity and BActivity.
Apparently, the issue was with calling “finish()” in the onCreate of BaseActivity. Moving the finish() calls out of the BaseActivity onCreate calls and instead checking whether to call finish() in AActivity and BActivity fixed the problem.
Hopefully this is of use to someone else. I will change the title to better reflect the actual problem.