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.
In this code only MyApplication.getInstance() returning null would lead to a NullPointerException. If you want a more detailed explanation please supply the stacktrace and the MyApplication Singleton code.
I am not sure why you are implementing a Singleton pattern on the MyApplication class anyway. Your application is only going to run once, so no need for a Singleton. If you want to access your application instance in an activity you can use
MyApplication application = (MyApplication) getApplication();
Don't you have at least a stacktrace report? You're talking about a NPE but actually not where it is thrown. Sure you present the affected code?
My guess would be that you're relying on some code from previous activities, but since your application is restored the previous activities are not instantiated and the data is null. So I would recommend to search in onDestroy for such data dependent code because it will be called too.
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.
Related
I have some Apps where I use a static reference of the Application instance.
That's usefull when I need to use context in some singleton Class that has application lifetime.
Here an example:
public class MyApp extends Application
{
private static MyApp smApplication;
public MyApp()
{
MyApp.smApplication = this;
}
public void onCreate()
{
super.onCreate();
MyApp.smApplication = this;
}
public static MyApp getApp() {
return MyApp.smApplication;
}
}
class Settings // Example of Singleton class
{
...
public boolean loadSettings()
{
Context context = MyApp.getApp(); // NullPointerException on the next line
SharedPreferences pref = context.getSharedPreferences(SHAREDPREF_FILENAME, Context.MODE_PRIVATE);
...
}
}
This works like a charm in the majority of the cases.
But... I have a number of NullPointerException crashes reported in the Play Console about that Context. Usually called in the MainActivity.onCreate or MyService.onCreate.
Application should Always be created before any other Activiy or Service. So I can't understand what happens. I've never had a similar crash on any of my devices.
smApplication is initialized in the constructor and never set to null.
It seems that in that cases Application is not created. It's also weird that all these crashes are reported in the PlayConsole but I cannot find them in Firebase Crashlitics as if neither Crashlitics has yet initialized in that cases (and FC shoul be initialized by the Application)
This has been happening for years in a small part of my users.
Any suggestion?
PS. I Do not need suggestion on code refactoring, just to understand what happens and how to avoid it.
I started getting this illegal state exception recently.
This is the stack trace:
E/AndroidRuntime: FATAL EXCEPTION: UploaderServiceThread1640451978001
Process: com.sister.ivana4k, PID: 2032
java.lang.IllegalStateException: Method addObserver must be called on the main thread
at androidx.lifecycle.LifecycleRegistry.enforceMainThreadIfNeeded(LifecycleRegistry.java:317)
at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.java:172)
at androidx.activity.ComponentActivity.(ComponentActivity.java:231)
at androidx.fragment.app.FragmentActivity.(FragmentActivity.java:127)
at androidx.appcompat.app.AppCompatActivity.(AppCompatActivity.java:87)
at com.sister.ivana.database.OrmLiteBaseAppCompatActivity.(OrmLiteBaseAppCompatActivity.java:33)
at com.sister.ivana.database.DBServices.VehicleServices.(VehicleServices.java:28)
at com.sister.ivana.upload.UploadType.getFileURL(UploadType.java:548)
at com.sister.ivana.upload.UploadType.createSpinItPicturesUploadDescription(UploadType.java:475)
at com.sister.ivana.upload.UploadType.getUploadRequest(UploadType.java:299)
at com.sister.ivana.upload.Uploader.startCompletionRequest(Uploader.java:704)
at com.sister.ivana.upload.Uploader.processQueue(Uploader.java:443)
at com.sister.ivana.upload.Uploader.handleMessage(Uploader.java:198)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.os.HandlerThread.run(HandlerThread.java:67)
I have searched around and found that I could potentially wrap the call to do it on the main thread, unfortunately from what I can see the call is made by an internal library so I am not sure how I could resolve it or at least mitigate it.
What can I do? Let me know if you need more info.
Vehicle Services class:
public class VehicleServices extends OrmLiteBaseAppCompatActivity {
private final String vinNumber;
private final Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public VehicleServices(String vinNumber, Context context) { //line 28
this.vinNumber = vinNumber;
this.context = context;
}
public Project getProject() {
try {
DatabaseHelper helper = getHelperInternal(this.context);
final Vehicle vehicle = helper.getVehicleDao().queryForId(this.vinNumber);
if (vehicle != null) {
Dao<Project, ?> dao = helper.getProjectDao();
for (Project project : dao) {
final String projectID = project.getProject().replace(",", "");
if (projectID.equals(vehicle.getProject())) {
return project;
}
}
}
} catch (SQLException ex) {
Util.logError("Database error adding new VIN", ex);
}
return null;
}
}
I have to also mention that I inherited this codebase a few days ago and I am aware that best practices were thrown out when building this. (Memory leaks and bugs everywhere, spaghetti code, you name it) I am looking for a way to fix this particular exception to the greatest degree possible.
I have access to all the files except android internal libraries.
I have a WebView in the layout xml of my MainActivity, to which I setWebViewClient(new WebViewClient()), followed by loadUrl(...) in onCreate.
Most of the time the app runs fine and the Web content is displayed correctly.
But in some cases, opening the app causes a crash. I've noticed that it happens when the app scheduled a PendingIntent broadcast with AlarmManager, which triggers a Notification whose contentIntent is a PendingIntent.getActivity set to launch MainActivity.
But it happens only in the case when the user has removed the app from the stack of active apps in the meantime (Notification is visible, not yet clicked, and stack if apps cleared. So, app process probably stopped?).
Seemingly no other system modifications in between (in particular no app/system update, no playing around with user profiles or Chrome app.)
Stack trace:
java.lang.RuntimeException:
at android.webkit.WebViewDelegate.getPackageId (WebViewDelegate.java:164)
at yj.a (PG:16)
at xH.run (PG:14)
at java.lang.Thread.run (Thread.java:764)
Occurs with Android 7.0 thru 9. Also, seems to have started to occur when I upgraded target SDK to 28.
I don't use explicitly a WebViewDelegate. It must be internal system code (hence the obfuscation).
By reading the source code of AOSP, it seems that the WebView fails to retrieve the package to which it belongs -- but why sometimes only!?
Any help appreciated! Thanks.
It has taken weeks of investigation on and off, but I've finally found why I'm seeing this issue. For me, it was just because I'd overridden the getResources() method in my application scope to use the current activity. Something like this:
public class MyApplication extends MultiDexApplication {
private static MyApplication sInstance = null;
private WeakReference<Activity> mCurrentActivity;
public static MyApplication getInstance() {
return sInstance;
}
public void setCurrentActivity(Activity activity) {
mCurrentActivity = new WeakReference<>(activity);
}
public Activity getCurrentActivity() {
return mCurrentActivity == null ? null : mCurrentActivity.get();
}
#Override
public Resources getResources() {
// This is a very BAD thing to do
Activity activity = getCurrentActivity();
if (activity != null) {
return activity.getResources();
}
return super.getResources();
}
}
This was done as a shortcut as I often wanted to get strings that were activity-specific, so I was calling MyApplication.getInstance().getResources().getString(). I now know this was a bad thing to do - removing my override of this method instantly fixed it.
So the key takeaway from this for me is that when the WebView is initialising, it MUST be able to get hold of the application context, so that the resources passed into WebViewDelegate.getPackageId() are at the application level - the activity context isn't enough, and causes this error.
As a side note - I wasn't even trying to add a WebView to my application. I was only actually using the following:
String userAgent = WebSettings.getDefaultUserAgent(this);
I was then passing this value into a custom media player that I'm using. Passing "this" as either application or activity scope always failed, due to my override.
Looking through documentation,you can see that error is thrown when package can't be found.Check your syntax ,package name and try again.
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/webkit/WebViewDelegate.java (Line 164)
/**
* Returns the package id of the given {#code packageName}.
*/
public int getPackageId(Resources resources, String packageName) {
SparseArray<String> packageIdentifiers =
resources.getAssets().getAssignedPackageIdentifiers();
for (int i = 0; i < packageIdentifiers.size(); i++) {
final String name = packageIdentifiers.valueAt(i);
if (packageName.equals(name)) {
return packageIdentifiers.keyAt(i);
}
}
throw new RuntimeException("Package not found: " + packageName);
}
In Developer Console I see a lot of crashes with stacktrace like this
java.lang.RuntimeException:
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2984)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3045)
at android.app.ActivityThread.-wrap14(ActivityThread.java:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1642)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method:0)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
Caused by: java.lang.ClassCastException:
at com.myapp.ui.BaseActivity.getApp(BaseActivity.java:193)
at com.myapp.ui.BaseActivity.onCreate(BaseActivity.java:275)
at com.myapp.ui.CastActivity.onCreate(CastActivity.java:39)
at com.myapp.ui.MainActivity.onCreate(MainActivity.java:268)
at android.app.Activity.performCreate(Activity.java:6955)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2927)
getApp method of BaseActivity is
public App getApp() {
return (App) getApplication();
}
App class is
public class App extends MultiDexApplication { ...
and in manifest application tag contains reference to this class
<application
android:name="com.myapp.App"
98% of crashes is for android 7.0, rest is 7.1. No other android versions are affected.
EDIT: I use proguard so it can be somehow related but keeping class
-keep class com.myapp.** { *;}
-keep interface com.myapp.** { *;}
Note: It may not be related but in same android versions it looks like App's onCreate method is sometimes not called. I observed it because some objects which are created in onCreate were null when they were accessed from Service (started by AlarmManager) or BroadcastReceiver
Does anyone has idea what can cause it, how to fix it or work around it? Thanks
EDIT 2:
I ended up with something like this:
public App getApp() {
Application application = getApplication();
App app = null;
try {
app = (App) application;
} catch (Exception e) {
if (application != null) {
Log.e(TAG, "getApp Exception: application class: " + application.getClass().getName());
} else {
Log.e(TAG, "getApp Exception: application object is null");
}
}
return app;
}
It at least doesn't crash and I can check getApp() == null
Casting fails because getApplication() returns an Application and NOT the desired sub-class.
I've had some success where I caught the error and asked the user to reboot their device or reinstall the app.
Unfortunately, there's no real fix to this rare crash. Google won't fix the lifecycle-related issue, but said it reduced in Android 7.1+. Source: https://issuetracker.google.com/issues/37137009
I think you should cast getApplicationContext() into App instead.
While I cannot say if this solution works.
I think that static Application instance should solve the problem.
class MyApp extends Application {
private static final sInstance;
public void onCreate() {
sInstance = this;
}
public static MyApp getInstance() {
return sInstance;
}
}
Instead of calling getActivity() if you call MyApp.getInstance() you should not need to cast. So there should not be any ClassCastException
anymore.
You should override attachBaseContext in your application class like this:
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
Check this link for more information: https://developer.android.com/reference/android/support/multidex/MultiDexApplication.html
This might help
public class App extends MultiDexApplication {
public static App app = null;
public static App getInstance() {
return app;
}
#Override
public void onCreate() {
super.onCreate();
app = this;
}
}
you doesn't need to cast getApplication(), reason is you are already in Application class so simply just use this keyword to get application instance. Hope you find useful
I am trying to write Unit test cases for Activities in my app by extending the test class with ActivityUnitTestCase. I could successfully run the test cases earlier but now I'm always getting the exception while running them. Even though I'm pretty familiar with handling NullPointerExceptions, I couldn't figure out the problem that's causing this. I couldn't find any similar questions so I'm posting this one.
Stack trace shows me there is a null object reference at this line in my code
activity = startActivity(mIntent, null, null);
But the startActivity method is supposed to get the instance of the activity I'm testing. I'm not sure why it's returning null.
Here is the Stack trace.
java.lang.NullPointerException: Attempt to write to field 'android.os.IBinder android.app.ActivityThread.mLastIntendedActivityToken' on a null object reference
at android.app.Activity.performCreate(Activity.java:6372)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
at android.support.test.runner.MonitoringInstrumentation.callActivityOnCreate(MonitoringInstrumentation.java:346)
at android.test.ActivityUnitTestCase.startActivity(ActivityUnitTestCase.java:158)
at com.abc.test.MainActivityTest.access$100(MainActivityTest.java:16)
at com.abc.test.MainActivityTest$1.run(MainActivityTest.java:34)
at android.app.Instrumentation$SyncRunnable.run(Instrumentation.java:1891)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6117)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
Test running failed: Instrumentation run failed due to 'java.lang.NullPointerException'
Here is the Test class
public class MainActivityTest extends ActivityUnitTestCase<MainActivity>{
private Intent mIntent;
private MainActivity activity;
public MainActivityTest() {
super(MainActivity.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
//Create an intent to launch target Activity as it is not automatically started by Android Instrumentation
mIntent = new Intent(getInstrumentation().getContext(), MainActivity.class);
//Start the activity under test in isolation, in the main thread to avoid assertion error.
getInstrumentation().runOnMainSync(new Runnable() {
#Override
public void run() {
activity = startActivity(mIntent, null, null);
}
});
}
#Override
protected void tearDown() throws Exception {
super.tearDown();
}
/**
* Tests the preconditions of this test fixture.
*/
#SmallTest
public void testPreconditions() {
assertNotNull("MainActivity is null", getActivity());
}
#MediumTest
public void testSecondActivityWasLaunchedWithIntent() {
// Get the intent for the next started activity
final Intent launchIntent = getStartedActivityIntent();
//Verify the intent was not null.
assertNotNull("Intent was null", launchIntent);
//Verify that LaunchActivity was finished
assertTrue(isFinishCalled());
}
}
#prudhvi I don't think I have a silver bullet, unfortunately, but I would suggest trying to follow these steps to upgrade to the new test support libraries in the newer versions of the SDK. Sorry that I can't be of more help!
I had the same issue.
The solution was to make the test an ActivityInstrumentationTestCase2 instead of an ActivityUnitTestCase, and have the activity created for me in the background
There's a good chance something in your application class (i.e. X extends Application) is crashing early on. If that's the case you'll see this error.... Checkout your logcat for traces.
i changed ActivityUnitTestCase to ActivityInstrumentationTestCase2 and removed my startActivity() calls (seems that ActivityInstrumentationTestCase2 automatically starts the activity) now it runs again