RuntimeException with Dagger 2 on Android 7.0 and Samsung devices RuntimeException with Dagger 2 on Android 7.0 and Samsung devices android android

RuntimeException with Dagger 2 on Android 7.0 and Samsung devices


Finally I found a way to resolve the crashes caused by using Dagger 2 under Android 7.0 for my application. Please note that this does not resolve the issue with a custom application not being properly used under Android 7.0. In my case I did not have important logic in my custom Application besides getting Dagger 2 implemented and so I just replaced the DaggerApplication based implementation with the ApplicationlessInjection below.

Known issues

  • No dependency injection in custom application classes (probably this isn't a good idea with the freaking Android 7.0 OEM implementations anyway)
  • Not all Dagger components where modified by me, I replaced only DaggerAppCompatActivity, DaggerIntentService and DaggerFragment. If you are using other components like DaggerDialogFragment or DaggerBroadcastReceiver you need to create your own implements but I guess that should not be too hard :)

Implementation

Stop using DaggerApplication. Either extend your custom application again from the standard Application or get rid of the custom application entirely. For the dependency injection with Dagger 2 its not needed anymore. Just extend e.g. FixedDaggerAppCompatActivity and you are good to go with the Dagger 2 DI for activities.

You may notice that I am still passing the application context to the ApplicationlessInjection.getInstance(). The dependency injection itself does not need the context at all but I want to be able to easily inject the application context into my other components and modules. And there I do not care if the application context is my custom App or some crazy other stuff from Android 7.0 as long as it is a context.

ApplicationlessInjection

public class ApplicationlessInjection        implements            HasActivityInjector,            HasFragmentInjector,            HasSupportFragmentInjector,            HasServiceInjector,            HasBroadcastReceiverInjector,            HasContentProviderInjector {    private static ApplicationlessInjection instance = null;    @Inject DispatchingAndroidInjector<Activity> activityInjector;    @Inject DispatchingAndroidInjector<BroadcastReceiver> broadcastReceiverInjector;    @Inject DispatchingAndroidInjector<android.app.Fragment> fragmentInjector;    @Inject DispatchingAndroidInjector<Fragment> supportFragmentInjector;    @Inject DispatchingAndroidInjector<Service> serviceInjector;    @Inject DispatchingAndroidInjector<ContentProvider> contentProviderInjector;    public ApplicationlessInjection(Context applicationContext) {        AppComponent appComponent = DaggerAppComponent.builder().context(applicationContext).build();        appComponent.inject(this);    }    @Override    public DispatchingAndroidInjector<Activity> activityInjector() {        return activityInjector;    }    @Override    public DispatchingAndroidInjector<android.app.Fragment> fragmentInjector() {        return fragmentInjector;    }    @Override    public DispatchingAndroidInjector<Fragment> supportFragmentInjector() {        return supportFragmentInjector;    }    @Override    public DispatchingAndroidInjector<BroadcastReceiver> broadcastReceiverInjector() {        return broadcastReceiverInjector;    }    @Override    public DispatchingAndroidInjector<Service> serviceInjector() {        return serviceInjector;    }    @Override    public AndroidInjector<ContentProvider> contentProviderInjector() {        return contentProviderInjector;    }    public static ApplicationlessInjection getInstance(Context applicationContext) {        if(instance == null) {            synchronized(ApplicationlessInjection.class) {                if (instance == null) {                    instance = new ApplicationlessInjection(applicationContext);                }            }        }        return instance;    }}

FixedDaggerAppCompatActivity

public abstract class FixedDaggerAppCompatActivity extends AppCompatActivity implements HasFragmentInjector, HasSupportFragmentInjector {    @Inject DispatchingAndroidInjector<Fragment> supportFragmentInjector;    @Inject DispatchingAndroidInjector<android.app.Fragment> frameworkFragmentInjector;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        inject();        super.onCreate(savedInstanceState);    }    @Override    public AndroidInjector<Fragment> supportFragmentInjector() {        return supportFragmentInjector;    }    @Override    public AndroidInjector<android.app.Fragment> fragmentInjector() {        return frameworkFragmentInjector;    }    private void inject() {        ApplicationlessInjection injection = ApplicationlessInjection.getInstance(getApplicationContext());        AndroidInjector<Activity> activityInjector = injection.activityInjector();        if (activityInjector == null) {            throw new NullPointerException("ApplicationlessInjection.activityInjector() returned null");        }        activityInjector.inject(this);    }}

FixedDaggerFragment

public abstract class FixedDaggerFragment extends Fragment implements HasSupportFragmentInjector {    @Inject DispatchingAndroidInjector<Fragment> childFragmentInjector;    @Override    public void onAttach(Context context) {        inject();        super.onAttach(context);    }    @Override    public AndroidInjector<Fragment> supportFragmentInjector() {        return childFragmentInjector;    }    public void inject() {        HasSupportFragmentInjector hasSupportFragmentInjector = findHasFragmentInjector();        AndroidInjector<Fragment> fragmentInjector = hasSupportFragmentInjector.supportFragmentInjector();        if (fragmentInjector == null) {            throw new NullPointerException(String.format("%s.supportFragmentInjector() returned null", hasSupportFragmentInjector.getClass().getCanonicalName()));        }        fragmentInjector.inject(this);    }    private HasSupportFragmentInjector findHasFragmentInjector() {        Fragment parentFragment = this;        while ((parentFragment = parentFragment.getParentFragment()) != null) {            if (parentFragment instanceof HasSupportFragmentInjector) {                return (HasSupportFragmentInjector) parentFragment;            }        }        Activity activity = getActivity();        if (activity instanceof HasSupportFragmentInjector) {            return (HasSupportFragmentInjector) activity;        }        ApplicationlessInjection injection = ApplicationlessInjection.getInstance(activity.getApplicationContext());        if (injection != null) {            return injection;        }        throw new IllegalArgumentException(String.format("No injector was found for %s", getClass().getCanonicalName()));    }}

FixedDaggerIntentService

public abstract class FixedDaggerIntentService extends IntentService {    public FixedDaggerIntentService(String name) {        super(name);    }    @Override    public void onCreate() {        inject();        super.onCreate();    }    private void inject() {        ApplicationlessInjection injection = ApplicationlessInjection.getInstance(getApplicationContext());        AndroidInjector<Service> serviceInjector = injection.serviceInjector();        if (serviceInjector == null) {            throw new NullPointerException("ApplicationlessInjection.serviceInjector() returned null");        }        serviceInjector.inject(this);    }}

My AppComponent

@Singleton@Component(modules = {        AppModule.class,        ActivityBindingModule.class,        AndroidSupportInjectionModule.class})public interface AppComponent extends AndroidInjector<ApplicationlessInjection> {    @Override    void inject(ApplicationlessInjection instance);    @Component.Builder    interface Builder {        @BindsInstance        AppComponent.Builder context(Context applicationContext);        AppComponent build();    }}

My AppModule

@Modulepublic abstract class AppModule {    @Binds    @ApplicationContext    abstract Context bindContext(Context applicationContext);}

And for the sake of completeness my @ApplicationContext annotation

@Qualifier@Retention(RetentionPolicy.RUNTIME)public @interface ApplicationContext {}

Hopefully I can help someone else with my code as well. For me I could resolve all crashes related to introducing Dagger 2 and the weird Android 7.0 versions.

If more clarification is needed just let me know!


I encountered the same problem in my app and i resolved it by using below code :

Application app = activity.getApplication();if(app == null) {     app = (Application)activity.getApplicationContext();}