3

I have been receiving some crash reports in the Play Store which initially seemed crazy to me. Some activities (in 1 case, it's a broadcast receiver) are crashing in onCreate()/onResume() due to NullPointerException.

These activities are using static methods which in turn use the Application singleton [for context], but the object returned is null like if the application object didn't exist at all. From my understanding, the application should always have an instance.

My code is ordinary, the application sets a static field in its onCreate(), and the classes that the activities call use MyApplication.getInstance() which returns the application object.

How can MyApplication.getInstance() return null when called from activities? I have no idea how that could happen.

Of course, I have been unable to replicate this crash. This mainly happens in Android 6, but I have some reports from Android 8 and 9.

  • Why do you need application context? Can you use your activity's context instead? Depending on application context isn't usually something you want to do. – brandonx Apr 09 '19 at 17:14

3 Answers3

2

I guess you are doing what the most voted answer says in this question. However, you should see what many people warn in the comments:

The downside is that there is no guarantee that the non-static onCreate() will have been called before some static initialization code tries to fetch your Context object. That means your calling code will need to be ready to deal with null values which sort of defeats the whole point of this question. – Melinda Green

.

It's upsetting to see how many upvotes this answer has. You should never hold a static instance to context - for proofs sake, try using Leak Canary (github.com/square/leakcanary) and find the memory leak caused because of this. @people-with-enouhg-rep-and-Android-knowledge, please re-review this answer and act accordingly. This is guaranteed to be used by beginners and it's plain simple wrong. – Crearo Rotar

You should either:

  • User your Activity context whenever possible and pass it to any other class that needs it.
  • Or, what I really recommend, set up dependency injection using Dagger2. It is a little difficult to learn at the beginning, but there is a lot of information and tutorials to help you get started. Once you setup Dagger properly, all you need to access you Application context in a null-safe way is Inject it in the corresponding class like this:

    public class MyClass {
    
        @Inject
        Context context;
    
    
        ...
    
    }
    
dglozano
  • 6,369
  • 2
  • 19
  • 38
0

As an alternative to the other answer about dagger dependency injection I just wanted to give an example of getting context from an activity the old fashioned way. If you declare context as a member variable it will be available all over your activity and can be passed to other classes as needed:

public class ExampleActivity extends AppCompatActivity {

    private Context mContext;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_example);
        mContext = this;
    }
brandonx
  • 228
  • 2
  • 13
0

I think I found the cause. In Android 6 auto restore not initializing app, the problem is the same and they identified the cause as being the auto backup feature that was introduced in Android 6. Basically, after a restore from the backup, the app is restarted in a weird way where the Application object is not created before the Activity. We now can reproduce the problem and disabling backup fixes the problem.