According to Dagger documentation about injecting activity objects, it says that installing AndroidInjectionModule in your application component. However, everything is fine without it.
Does it means that I don't need to declare it? Under what circumstances will it be wrong?
For example:
Injected instance
data class Food(val name: String)
Module
#Module
class FoodModule{
#Provides
fun provideFood(): Food {
return Food("cholocate")
}
}
BindingModule
#Module
abstract class MainActivityModule {
#ContributesAndroidInjector(modules = [FoodModule::class])
abstract fun FoodShop(): MainActivity
}
AppComponent (Without installing AndroidInjectionModule)
#Component(modules = [MainActivityModule::class])
interface AppComponent{
fun inject(app: App)
}
App
class App : Application(), HasActivityInjector {
#Inject
lateinit var dispatchingActivityInjector: DispatchingAndroidInjector<Activity>
override fun onCreate() {
super.onCreate()
DaggerAppComponent.create().inject(this)
}
override fun activityInjector(): AndroidInjector<Activity> {
return dispatchingActivityInjector
}
}
MainActivity
class MainActivity : AppCompatActivity() {
#Inject
lateinit var food: Food
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d("test", "Get ${food.name}")
}
}
It get chocolate successfully in MainActivity.
Does it means that I don't need to declare it? Under what circumstances will it be wrong?
It actually seems like you don't need to declare it, but it might lead to compile errors if you don't.
If you have a look at AndroidInjectionModule you can see that it just lists a bunch of #Multibinds methods for framework types.
#Multibinds
abstract Map<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>>
activityInjectorFactories();
Now if you look up Declaring #Multibinds you can read that
You do not have to use #Multibinds for sets or maps that have at least one #IntoSet, #ElementsIntoSet, or #IntoMap binding, but you do have to declare them if they may be empty.
And to declare them if they may be empty is exactly what the AndroidInjectionModule module is doing for you. If the Android Injection parts would require an undefined Map of injector factories you would probably get a compile time error stating that it cannot be provided.
The reason that you don't need the module is because you're using #ContributesAndroidInjector, of which the generated code will contain a #Binds #IntoMap etc. method, that declares the bindings map. Stated above—as it is not empty anymore—you would not need the additional #Multibinds declaration that AndroidInjectionModule provides for the non-empty multibinding.
You might not need the module, but it will declare all the framework injector factories for you in case that they might be empty, possibly preventing one or two compile errors. After all the javadoc simply states that it should be installed, not that it must.
This module should be installed in the component that is used to inject the Application class.
Related
I've been trying to find a way to provide dependencies depending where a fragment is navigated from. I have the following in a library module:
interface FruitProvider {
fun provide(): String
}
class FruitFragment : Fragment() {
#Inject
lateinit var provider: FruitProvider
override fun onAttach(context: Context) {
AndroidSupportInjection.inject(this)
super.onAttach(context)
}
}
The idea is for other modules to consume this library and inject whatever they want as a FruitProvider.
As an example, if I have 2 providers:
class BananaProvider #Inject constructor() : FruitProvider {
override fun provide() = "banana"
}
class PearProvider #Inject constructor() : FruitProvider {
override fun provide() = "pear"
}
If I'm in the banana module I'd like to create and display an instance of FruitFragment injected with BananaProvider. Similarly for the pear module but with a PearProvider.
Background
Right now we have a method in FruitFragment to set the provider, i.e., setFruitProvider(provider: FruitProvider) that is called by the consumers of the library.
This approach is not ideal because if the activity gets recreated this field is null. At least this is what some debugging seems to suggest. Put simply, the fragment is recreated but the setFruitProvider is not being called again since it gets called from methods outside the fragment's lifecycle.
The interface FruitProvider cannot be Serializable so we cannot save it in the instance state. All that we think is left is to inject the fragment since this can be done by the fragment itself when attached.
This question already has answers here:
Why #ContributesAndroidInjector doesn't provide Android Framework type
(2 answers)
Closed 3 years ago.
I have two provision methods, one depending on the object the other method provides. Below code works properly the problem is stated under the section of Problem
Working Example
In StringProviderModule, added a method which is dependent on the object (Fragment instance) provided in the parent component.
#Module
class StringProviderModule {
#Module
companion object{
#JvmStatic
#Provides
fun provideFragmentArgument(cripledFragment: CripledFragment): String{
return cripledFragment.arguments?.getString(CripledFragment.ARG_STRING) ?: "No such argument"
}
}
}
In FragmentModule, added StringProviderModule to FragmentModule's generated subcomponent
#Module
abstract class FragmentModule {
#ContributesAndroidInjector(modules = [StringProviderModule::class])
abstract fun fragment: CripledFragment
}
In ActivityBinderModule, adding FragmentModule to the ActivityBinderModule's generated subcomponent
#Module
abstract class ActivityBinderModule {
#ContributesAndroidInjector(modules = [FragmentModule::class])
abstract fun mainActivity(): MainActivity
}
In AppComponent, adding ActivityBinderModule as a module
#Component(modules = [
AndroidSupportInjectionModule::class,
ActivityBinderModule::class
])
interface AppComponent: AndroidInjector<DaggerMyApp> {
#Component.Builder
interface Builder{
#BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
}
Then #Injecting String into Presenter class and #Injecting that presenter into CripledFragment. I can access Fragment's String argument in Presenter. Implementation is not important as it's outside the scope of the question, I can add code if needed, though.
Problem
When merging StringProviderModule and FragmentModule, IDE complains with following message "CripledFragment cannot be provided without an #Inject constructor or an #Provides-annotated method". Isn't #ContributesAndroidInjector already providing an instance of CripledFragment?
#Module
abstract class FragmentModule {
#ContributesAndroidInjector
abstract fun cripledFragment(): CripledFragment
#Module
companion object{
#JvmStatic
#Provides
fun provideFragmentArgument(cripledFragment: CripledFragment): String{
return cripledFragment.arguments?.getString(CripledFragment.ARG_STRING) ?: "No such argument"
}
}
}
I have checked multiple tutorials and dagger docs, couldn't find any proper explanation to infer the cause of my problem. Simple explanation rather than suggesting a solution is much appreciated as I'm not looking for a concrete solution.
This question has been answered here. Basically, #ContributesAndroidInjector provides MainActivity instance for a subcomponent it generates not for a module (in this case ActivityBinderModule) it resides in. That means any provision method inside FragmentModule will have access to MainActivity's instance.
#Module
abstract class ActivityBinderModule {
#ContributesAndroidInjector(modules = [FragmentModule::class])
abstract fun mainActivity(): MainActivity
}
As you see in example,
I have Core class for distribute the shared variables/methods etc. into the mixins.
Abstract class for defining necessary methods, providing summary about api.
Main class for importing everything like a provider.
There isn't any runtime error of course.
Problem with this approach, mixin methods does not recognize #override annotation.
I want to create granular, clean structure for my packages. What is the best approach for this situation or what is the mistake I'm doing?
abstract class AbstractCore {
void foo();
void bar();
}
class Core {
var shared;
}
mixin Feature1 on Core {
#override // not recognized by syntax of course
void foo() {
// something with [shared]
}
}
mixin Feature2 on Core {
#override // not recognized
void bar() {
// yet another thing with [shared]
}
}
class Main with Core, Feature1, Feature2 implements AbstractCore {}
You can accept like:
Core: ApiBase(For sharing Client object, constants, keeping dispose method...)
Feature1: let's say Authentication related Api calls
Feature2: let's say Content related Api calls
Main: Api provider.
Annotations don't have any impact on what the code do. They are just used for readability and tooling.
In your care, it is the analyzer that is complaining about #override, because you're not overriding anything.
Simply remove the #override decorator — it wasn't needed to begin with.
Looking at the source code for the Android Architecture Components sample GithubBrowerSample, I don't understand the point of double injecting the githubApp.
Wouldn't the inject method be enough? Why do it need both of them in the same sentence?
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance Builder application(Application application);
AppComponent build();
}
void inject(GithubApp githubApp);
}
And they use it like:
public static void init(GithubApp githubApp) {
DaggerAppComponent.builder().application(githubApp)
.build().inject(githubApp);
As Thomas Broyer described, you've got two separate directions to set up: You want the Dagger graph to know how to get to your Application instance, and you want to get access to certain bindings out of the dependency graph.
The #BindsInstance line in the Builder creates a binding for Application set to the instance you pass in. It sounds like you understand this part.
However, after you've created your Component, presumably you want to use it. Let's say you want to get fully-injected instances of classes Dep1, Dep2, and Dep3 out of your graph. One way you could do this is to create methods on your Component that get the instances:
#Singleton #Component(/* ... */) interface AppComponent {
// [builder snipped out here]
fun getDep1(): Dep1
fun getDep2(): Dep2
fun getDep3(): Dep3
}
And then you call those as part of your App creation.
var appComponent = DaggerAppComponent.builder().application(githubApp).build()
var dep1 = appComponent.getDep1()
var dep2 = appComponent.getDep2()
var dep3 = appComponent.getDep3()
// Use dep1, dep2, and dep3 here.
However, you can also create a single-arg method, which is typically a void method called inject. This populates all of the #Inject-annotated fields and calls all of the #Inject-annotated methods on the instance you pass in. If GitHubApp has #Inject-annotated-fields (and it does), the call to inject lets you skip defining all of the getters on the Component. That reduces all of the above code to:
DaggerAppComponent.builder().application(githubApp)
.build().inject(githubApp)
...which is what you see in the demo.
The #BindsInstance tells Dagger that it should inject the application into whichever #Inject Application it finds in the dependency graph.
The second asks Dagger to inject dependencies into it's #Inject-annotated fields and methods. This the root of the dependency graph.
Technically, the component method can be called as many times as you like, while the builder method can only be called once.
It seems Guice is ignoring my #Provider methods of my module.
I have a class MyModule like this:
public class MyModule extends AbstractModule {
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(Timed.class), new GuiceEnabledLoggingInterceptor());
bind(OneClass.class).to(OneClassImpl.class);
// And more binding lines...
}
#Provides
public AnotherClassInApi provideMyClass() {
return AnotherClassInApi.getInstance();
}
// And more #Provides methods
}
Main method is
public static void main(String[] args){
ConfigHandler.getInstance().loadConfigWhenNotRunningInsideMicrocontainer();
Injector INJECTOR = Guice.createInjector(new MyModule());
// ...
}
In some other part of the project I have class AnotherClassInApi, which is a very standard singleton plus one method:
public class AnotherClassInApi {
private static final AnotherClassInApi INSTANCE = new AnotherClassInApi();
private AnotherClassInApi() { }
// ... more methods
public static AnotherClassInApi getInstance() {
return INSTANCE;
}
}
Well, I understand that should effectively bind any request for an AnotherClassInApi object to the getInstance() method, but it doesn't work. Funny thing, a breakpoint in the #Provide method is never reached while debugging, but one in the configure method is reached. It seems guice is ignoring my provider annotation, and I think I'm following exactly what Guice guide says about #Provider, so I'm already stuck.
I've been googling around, but can't find anything similar. Any help will be much appreciated.
Thanks!
The concept of Providers (and #Provides methods) is, that they are only called when actually needed. So unless you really use your Injector to create an instance that has an #Inject dependency, your Provider is not ignored, just not used (nor needed).
You can monitor all configured bindings by using "injector.getAllBindings()".
java.util.Map,Binding> getAllBindings()
Returns a snapshot
of this injector's bindings, both explicit and just-in-time. The
returned map is immutable; it contains only the bindings that were
present when getAllBindings() was invoked. Just-in-time bindings are
only present if they have been requested at least once. Subsequent
calls may return a map with additional just-in-time bindings. The
returned map does not include bindings inherited from a parent
injector, should one exist.
This method is part of the Guice SPI and is intended for use by tools
and extensions.