ClassCastException при внедрении зависимостей с помощью кинжала

Я использую Dagger2 для внедрения своих зависимостей во все мои приложения.

Несколько дней назад я начал получать отчеты о сбоях для одного из приложений от устройств Samsung Android 7.0 (только эти).

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:

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();
    }
}

Соответствующая часть класса BaseActivity:

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

И, наконец, часть StartupActivity:

@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);
}

Я уже обновил Dagger до самой последней версии (пока 2.11). Но у меня нет никаких идей по этому вопросу. Кроме того, я не могу воспроизвести его на своем устройстве Samsung S8 7.0.

Так что если у вас есть какие-либо идеи, пожалуйста, дайте мне знать!

Ваше здоровье

Изменить: Если кто-то столкнется с этой проблемой. Взгляните сюда: RuntimeException с Dagger 2 на Android 7.0 и устройствах Samsung Это может быть вашим решением.


person chrjs    schedule 28.06.2017    source источник
comment
о проблеме сообщается здесь: issuetracker.google.com/issues/37137009.   -  person Frank    schedule 01.06.2018


Ответы (1)


К Даггеру это не имеет никакого отношения. Проблема здесь:

return (MyApplication) context.getApplicationContext();

Context, возвращенный getApplicationContext(), не гарантированно будет вашим экземпляром Application. Единственная ситуация, с которой я столкнулся, когда этого не было, была в эмуляторе, но это всегда возможно.

Я предпочитаю этот подход:

private static MyApplication gInstance;

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

public static MyApplication instance() {
    return gInstance;
}

Это безопасно, потому что экземпляр Application создается, а его onCreate вызывается до создания любого другого компонента Android.

person Kevin Krumwiede    schedule 28.06.2017
comment
Спасибо за ваши предложения. К сожалению, эти изменения вызывают NullpointerExceptions доступ к экземпляру. Как это вообще возможно? :/ - person chrjs; 03.07.2017
comment
@chrjs Вы установили свой собственный класс приложения в манифесте? Вызываете ли вы instance() вне метода жизненного цикла (например, в инициализаторе поля?) - person Kevin Krumwiede; 03.07.2017
comment
Да, это установлено в манифесте. Доступ к нему осуществляется только через onCreate BaseActivity. - person chrjs; 03.07.2017
comment
Итак, ваш код в BaseActivity теперь выглядит как MyApplication.instance().getAppComponent().inject(this);? Вы пытались разбить это, чтобы увидеть, какой метод возвращает null? - person Kevin Krumwiede; 04.07.2017
comment
В яблочко. Моя проблема в том, что я не могу воспроизвести эту проблему на своих устройствах. Экземпляр всегда устанавливается перед вызовом вызова в действии. - person chrjs; 04.07.2017
comment
@chrjs Проблемы, которые можно воспроизвести только на определенных устройствах, — это кошмар. :-/ Вы когда-нибудь узнавали об этом что-нибудь еще? - person Kevin Krumwiede; 17.07.2017
comment
К сожалению нет. Я все еще застрял со странными исключениями NullPointerExeptions, обращающимися к экземпляру приложения. Извиняюсь. :/ - person chrjs; 18.07.2017