dagger: Dagger Application injection NPE

I’m trying to inject some objects on application, in order to access them whenever I want. So, on my application I’m doing something like this:

private static AppComponent mApplicationComponent;

@Override
    public void onCreate() {
        …
       mApplicationComponent = DaggerAppComponent.builder()
                .appModule(new AppModule(this, new ModuleSpref(this))
                .build();
   }

 public static AppComponent getInstance() {
        return mApplicationComponent;
    }

However, according to google crash log of my production app, the application has a NullPointException when trying to access anything from getInstance(). On my application this happens on a service which is only called via a receiver. Additionally, this also happens on another receiver.

 MyApplication.getInstance().context(); //Null Point Exception :(

Here is my ApplicationComponent:

@Component(modules = AppModule.class)
@Singleton
public interface AppComponent {
    void inject(Context context);

    //Exposed to sub-graphs.
    Context context();
    ModuleSpref getSpref();
}

I tried many times to replicate, but so far without success, despite the google crash saying otherwise. Am I doing something wrong here? As far as I know, for services/receivers to be initialised in android, the application must first be initialised, so getInstance() should not return null right?

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 4
  • Comments: 31 (2 by maintainers)

Most upvoted comments

No

On Tue, Oct 17, 2017, 12:12 PM Ron Shapiro notifications@github.com wrote:

@Zhuinden https://github.com/zhuinden is this what you’re referring too: square/mortar@bf74e3e https://github.com/square/mortar/commit/bf74e3e0ad00713c3123b957a61f82bd73b578b5 ?

Is there any reason to not just call (Application) activity.getApplicationContext() here then and not worry about the null-check?

/cc @rjrjr https://github.com/rjrjr @loganj https://github.com/loganj

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/google/dagger/issues/748#issuecomment-337272449, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEWPEtAeiU80PqYMRPwQN_rnusoFcks5stNHzgaJpZM4NjrJU .

@camsteffen if I understand the SO solution, it is just moving the component to a static variable? This would work for the production app, but keeping your DI graph in static state tends to cause problems for things like tests.

That’s never bothered anyone using Koin, which works exactly the same way.

Hope you had added application class name in the Android Manifest file. Without it, the app will work but the dagger component will be null.

One interesting thing to point out is that Android doesn’t always run any of the ContentProvider classes or the Application class listed in the manifest. https://developer.android.com/guide/topics/data/autobackup#ImplementingBackupAgent

Specifically… image

I’ve tested to see if Services and BroadcastReceivers still ran, and they do. This was causing multiple issues for me with Fabric, Firebase, and Dagger. I figured I’d share my findings here as I referenced this issue to try to fix my Dagger problem.

I’m in the process of disabling this auto backup (setting allowBackup="false" in the AndroidManifest) for the app I work on to validate my fix. I’ll post my findings if it fixes my Dagger issue.

I’m still pretty dumbfounded at what is happening here. I wish I had a better suggestion at what we should do.

Actually I found a work around for this which implies something like this on your application class:

public class MyApplication extends Application {
    private static MyApplication sInstance;
    private AppComponent applicationComponent;

    public MyApplication() {
        sInstance = this;
    } 

    public static AppComponent getInstance() {
        return sInstance.getAppComponent();
    }

    private AppComponent getAppComponent() {
        if (applicationComponent == null) {
            //initialise the dagger stuff here
        }
        return applicationComponent;
    }
}

Basically, if by any instance, the dagger app component builder returns null, it will force to initialise again. I know this is far from a perfect solution, but it works.

PS: I had multiple reports of different projects which the application was started after services/brodcasts and even activities on Samsung devices. I’m still investigating the issue, but I seen that Samsung starts a content provider for every application, maybe triggering this kind of behaviour. Although, with the above solution this kind of NPE no longer happened

Closing this as I don’t think there is much that can be done on the Dagger side. This feels like an Android bug that you can ever be called without the Application specified in the manifest.

@pablobaxter Any update?

@camsteffen Thank you for reminding me! Also sorry… I never did update my result on this thread as promised.

So disabling the backup worked for me. I am no longer seeing my Dagger crash, which in my case was a ClassCastException due to getApplication() not being an instance of DaggerApp, even though I extend it. This also solved one of the other issues I had, which would only ever happen if my extended Application class never ran.

I filed a ticket about this with Firebase (https://github.com/firebase/firebase-android-sdk/issues/1456), as this was the main library starting Services and BroadcastReceivers while the app was in this restricted mode. However, this is most likely an Android OS issue. It looks like whenever the app crashes in this restricted mode (in my case due to Firebase starting up), the next launch app (user initiated or otherwise) restarts the app in this restricted mode, which caused a crash, and so on.

Hope this helps!

I solved the issue for myself by not using anymore the DaggerApplication but an Application independent solution described here: https://stackoverflow.com/a/46925736/8788319

Not sure if this is an option for Dagger 2 but I did not find another way to resolve the crashes under Android 7.0 otherwise.

I am facing this issue as well and I have no idea how to work around it.

Caused by: java.lang.RuntimeException: 
  at dagger.android.AndroidInjection.inject (AndroidInjection.java:48)
  at dagger.android.support.DaggerAppCompatActivity.onCreate (DaggerAppCompatActivity.java:43)
  at com.package.MainActivity.onCreate (MainActivity.java:83)
  at android.app.Activity.performCreate (Activity.java:6912)
  at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1126)
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2900)

This happens only on Android 7.0, mainly on Samsung devices, some Huawai and Motorola devices and a few Xperia devices. I am unable to reproduce it since I do not have any of the affected devices at hand.

It seems this is caused by the application not (yet) being set for the activity, meaning activity’s onCreate is called before the activity is actually attached to the application.

Here the affected Dagger code:

https://github.com/google/dagger/blob/e8d7cd4c29c1316c5bb1cf0737d4f29111fcb1c8/java/dagger/android/support/DaggerAppCompatActivity.java#L42-L45

https://github.com/google/dagger/blob/e8d7cd4c29c1316c5bb1cf0737d4f29111fcb1c8/java/dagger/android/AndroidInjection.java#L43-L52

activity.getApplication() returns null, and so the RuntimeException is thrown.

Anyone any suggestions?