question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using Android injector with SDK-level-dependent components.

See original GitHub issue

I have a subclass of TileService (an android.app.Service that is only available on 24+). I want to use the Android injector and @ContributesAndroidInjector abstract MyTileService service(). This creates a service key of MyTileService.class in the generated module, ultimately resulting in the following as a field in my component.

this.mapOfClassOfAndProviderOfFactoryOfProvider =
        MapProviderFactory
            .<Class<? extends Service>, AndroidInjector.Factory<? extends Service>>builder(1)
            .put(MyTileService.class, bindAndroidInjectorFactoryProvider1)
            .build();

On Android versions <24, the reference to the class file tries to load the Android framework class (TileService) that doesn’t exist, crashing with a NoClassDefFoundError.

Can Dagger-Android do any clever lazy tricks to avoid this?

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:18 (3 by maintainers)

github_iconTop GitHub Comments

6reactions
tasomaniaccommented, Jan 20, 2019

For those who came across this issue. The solution was introduced in above commit.

You need to put the following argument to enable it. This will use Strings instead of Class references (which then fixes the mentioned crash). -Adagger.android.experimentalUseStringKeys

On Android java-only projects, you do

android {
    defaultConfig {
        javaCompileOptions.annotationProcessorOptions {
            arguments['dagger.android.experimentalUseStringKeys'] = 'true'
        }
    }
}

For Kotlin projects with kapt you would do

kapt {
  arguments {
    arg('dagger.android.experimentalUseStringKeys')
  }
}

Note: More explanation on how this works and its effects on Proguard/R8 is available here: https://github.com/google/dagger/blob/3a089646fb70fb5a193a731c4909d6ccaeeaadd3/java/dagger/android/processor/AndroidProcessor.java#L44-L52

Note 2: Keep in mind that enabling this also breaks incremental annotation processor support on Dagger 5.+

4reactions
markuspfeiffercommented, Mar 28, 2018

I’ve just run into the same issue using a subclass of JobService. Naturally the service is only used on devices running Android 5.x or newer.

As a possible way to add support for this in Dagger, how about using the @RequiresApi annotation?

@ContributesAndroidInjector
@RequiresApi(VERSION_CODES.LOLLIPOP)
JobService jobService();

If this annotation is present, the generated code could be modified to look like this:

private Map<Class<? extends Service>, Provider<AndroidInjector.Factory<? extends Service>>> getMapOfClassOfAndProviderOfFactoryOf3() {

  MapBuilder mapBuilder = MapBuilder.<Class<? extends Service>, Provider<AndroidInjector.Factory<? extends Service>>>newMapBuilder(3)
      .put(FooService.class, (Provider) fooServiceSubcomponentBuilderProvider)
      .put(BarService.class, (Provider) barServiceSubcomponentBuilderProvider);

  if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
      mapBuilder.put(JobService.class, (Provider) jobServiceSubcomponentBuilderProvider)
  }

  return mapBuilder.build();
}

~edit: Updated as per Jake Wharton’s comment. Thanks for the correction.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to use Android Injector for Activity and Fragment objects ...
I started to add AndroidInjectionModule as a module in the component. This module should be installed in the component that is used to...
Read more >
Using Dagger in Android apps
The Dagger basics page explained how Dagger can help you automate dependency injection in your app. With Dagger, you don't have to write ......
Read more >
Using Dagger 2 for dependency injection in Android - Tutorial
It extends the AndroidInjector to perform injection on a concrete Android component type (in our case MainActivity). 5.4. Update your Application class and ......
Read more >
Dependency Injection with Dagger 2 - CodePath Cliffnotes
Many Android apps rely on instantiating objects that often require other dependencies. ... The injector class used in Dagger 2 is called a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found