2

I'm using Dagger2 to inject my dependencies in all of my applications.

Some days ago I started getting Crash Reports for one of the applications from Samsung Android 7.0 (only these) devices.

java.lang.RuntimeException: 
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2924)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2985)
..
Caused by: java.lang.ClassCastException: 
  at de.package.name.MyApplication.get(MyApplication.java:43)
  at de.package.name.ui.base.BaseActivity.onCreate(BaseActivity.java:53)
  at de.package.name.ui.startup.StartupActivity.onCreate(StartupActivity.java:26)
  at android.app.Activity.performCreate(Activity.java:6912)
  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2877)

MyApplication class:

public class MyApplication extends MultiDexApplication {

    private AppComponent appComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        setupAppComponent();
    }

    private void setupAppComponent() {
        appComponent = DaggerAppComponent.builder()
                .appModule(new AppModule(this))
                .userApiModule(new UserApiModule())
                .build();
        appComponent.inject(this);
    }

    public static MyApplication get(Context context) {
        return (MyApplication) context.getApplicationContext();
    }
}

Relevant part of the BaseActivity class:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    MyApplication.get(this).getAppComponent().inject(this);
}

And finally, the StartupActivity Part:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setupComponent(MyApplication.get(this).getAppComponent());
    setContentView(R.layout.activity_startup);

    startupPresenter.bindView(this);
}

public void setupComponent(AppComponent appComponent) {
    startupComponent = DaggerStartupComponent.builder()
          .appComponent(appComponent)
          .startupModule(new StartupModule())
          .build();
    startupComponent.inject(this);
}

I already updated Dagger to the most recent version (2.11 for now). But I don't have any ideas about this issue. Also, I can't reproduce it on my Samsung S8 7.0 device.

So if you have any ideas, please let me know!

Cheers

edit: If anyone runs into this problem. Take a look here: RuntimeException with Dagger 2 on Android 7.0 and Samsung devices This might be your solution.

chrjs
  • 2,375
  • 1
  • 25
  • 41

1 Answers1

1

This has nothing to do with Dagger. The problem is here:

return (MyApplication) context.getApplicationContext();

The Context returned by getApplicationContext() is not guaranteed to be your Application instance. The only situation I've encountered where it wasn't was in an emulator, but it's always possible.

I prefer this approach:

private static MyApplication gInstance;

@Override
public void onCreate() {
    gInstance = this;
}

public static MyApplication instance() {
    return gInstance;
}

This is safe because the Application instance is created and its onCreate is called before any other Android component is created.

Kevin Krumwiede
  • 9,868
  • 4
  • 34
  • 82
  • Thanks for your suggestions. Unfortunately this changes cause `NullpointerExceptions` accessing the instance. How is this even possible? :/ – chrjs Jul 03 '17 at 06:49
  • @chrjs Did you set your custom application class in the manifest? Are you calling `instance()` outside of a lifecycle method (e.g., in a field initializer?) – Kevin Krumwiede Jul 03 '17 at 15:43
  • Yes, its set in the manifest. And is only accessed via `onCreate` of the BaseActivity – chrjs Jul 03 '17 at 19:19
  • So your code in `BaseActivity` now looks like `MyApplication.instance().getAppComponent().inject(this);`? Have you tried breaking that down to see which method is returning null? – Kevin Krumwiede Jul 03 '17 at 21:34
  • Exactly. My problem is, I can't reproduce this issue on my devices. The instance is always set before the get call is called in the Activity. – chrjs Jul 04 '17 at 06:00
  • @chrjs Issues that can only be reproduced on specific devices are a nightmare. :-/ Did you ever find out anything more about this? – Kevin Krumwiede Jul 17 '17 at 20:30
  • Unfortunately not. I'm still stuck with weird NullPointerExeptions accessing the instance of the Application. Sorry. :/ – chrjs Jul 18 '17 at 08:44