Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Building an Android Instant App with Application Component from Dagger

Tags:

I'm currently experimenting with InstantApps and would like to include dagger into my project.

I'm facing an issue setting up an application AppComponent. My application component includes all the feature dagger modules of my app.

I basically have:

  • One Base app module containing my Application class
  • Multiple features with each a dagger Module per Activity, all with Base as a dependency.
  • One app module and instant module both importing all the features and the base app module.

I'm trying to figure out the setup before adding the Instant App module.

From InstantApps documentation and project examples. It seems like the Application class needs to be in Base. From the Dagger documentation, to setup dagger:

 DaggerYourAppComponent.create().inject(this);

Should be included in your application class. However, this seems to be impossible as the AppComponent needs to reference all the feature dagger modules.

My questions are:

  • Where should I add my AppComponent dagger module?
  • Should I keep my application in the app module and not in Base?
  • Any GitHub repo or documentation around Dagger with Instant Apps?

Thank you

like image 983
Quentin Colle Avatar asked Jul 28 '17 18:07

Quentin Colle


2 Answers

  • Dagger2 is very much supported with Instant apps. You can create Component classes for each feature module and a corresponding Dagger provider class to expose the component class instance for each feature module.
  • Each module component class can declare inject methods for the classes contained only in that feature module.
  • In addition you can also have a Application component class in the base module for application wide injection.
  • The application component class can be instantiated in the Application class included in the base module and exposed to other feature modules via static method in the application class.

Here is a sample code of Dagger2 injection with Instant apps to make things clearer. https://github.com/willowtreeapps/android-instant-apps-demo

like image 160
Vishy Avatar answered Oct 12 '22 01:10

Vishy


I wrote an article about this with many details: Dagger2 for Modular Architecture, but following the short answer.

You have to use Dagger2 in a different way. Instead of using a module or subcomponent for each feature module, you need to use a component with a dependency to the base AppComponent.

In a single module we are usually do something like this:

@Singleton
@Component(modules = arrayOf(NetworkModule::class, RepositoryModule::class, 
                     SubcomponentModule::class))
interface ApplicationComponent : AndroidInjector<MyApplication> {
  val userRepository: UserRepository
  val apiService: ApiService
}

@Module
object NetworkModule {
  @Provides
  @Singleton
  @JvmStatic
  fun provideApiService(okHttp: OkHttp): ApiService {
    return ApiSerive(okHttp)
  }
 }

But as you said you don't have access to SubComponentModule that could be in another module or reference dagger modules in another feature module.

You can just create a new dagger module in a feature module depending on ApplicationComponent like this:

@Browser
@Component(modules = [(BrowserModule::class)],
      dependencies = [(AppComponent::class)])
interface BrowserComponent : AndroidInjector<AppCompatActivity> {
  @Component.Builder
  abstract class Builder: AndroidInjector.Builder<AppCompatActivity>(){
    /**
    *  explicity declare to Dagger2
    * that this builder will accept an AppComponent instance
    **/
    abstract fun plus(component: AppComponent): Builder
  }
}

And the corresponding feature activity will build the component:

class BrowserActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    DaggerBrowserComponent
        .builder()
        /**
         * we have to provide an instance of the AppComponent or
         * any other dependency for this component
         **/
        .plus((application as MyApplication).component)
        .build()
        .inject(this)
  }
}
like image 20
Luigi Papino Avatar answered Oct 12 '22 02:10

Luigi Papino