I have a question about dagger 2 and the possibilities to extends some components or modules.
In my case: I have a library (.aar file), it's part of the application.
Inside that file is defined AARComponent that has some modules e.g. AARActivityBuilder.
And that AARComponent is initialized in Application class.
#Component(modules = arrayOf(AndroidSupportInjectionModule::class, AARActivityBuilder::class, AARModule::class)
interface ApplicationComponent {
fun inject(app: AARApplication)
}
class AARApplication : Application() {
override fun onCreate() {
DaggerAARComponent
.builder()
.applicationModule(new AARModule(this))
.build()
.inject(this)
}
}
But the second part depends on that library and I'd like to add some modules (usually activities) that are defined only here.
But I want to use dependencies from the library as well.
Example:
AAR file has an abstract class A.
Application that imports aar library has class B that inhertis from class A.
So I need method with annotation #ContributesAndroidInjector which returns class B but .aar file does not know about class B.
I was trying to extend AARComponent but in vain. Also I was trying to create new #Component interface and add AARComponent as dependencies. But also did not work. Maybe I missed something or did wrong.
Is there any good method to do this?
Thanks
Related
I am experiencing an issue regarding access of an abstract class.
For background, I have an abstract class in a common module. The abstract class is just setters/getters for some values.
abstract class BaseConfiguration {
abstract var key: String?
abstract var token: String?
}
The common module is used by another module that is a SDK. So, in gradle this common module is implemented.
Gradle
implementation project(":common")
Inside of the SDK module, there are public interfaces to allow the setting/getting of the values in the BaseConfiguration file.
The conflict I am running into is that for Kotlin everything works fine. I am able to create a project, then add the SDK as a dependency and then set values for the BaseConfiguration through the provided interfaces in the SDK.
However, when I try to use the Java language, I am receiving a "cannot access BaseConfiguration" error. The only thing that seems to resolve this issue is to update my SDK gradle to api.
Gradle Changes
api project(":common")
I have concerns with this change, because the common module is supposed to be internal and only used by the SDK. The app level should not have access to it. The app should only access the provided interfaces by the SDK.
Does anyone know why this is working perfectly with Kotlin, but not with Java? What am I doing wrong?
Further Notes:
When decompiling the Kotlin to Java for the BaseConfiguration class it shows that everything is public.
public abstract class BaseConfiguration {
#Nullable
public abstract String getKey();
public abstract void setKey(#Nullable String var1);
#Nullable
public abstract String getToken();
public abstract void setToken(#Nullable String var1);
}
By default, java's class visibility is package private. That means any file in the same package can access your abstract BaseConfiguration.
In kotlin, the default is public.
I suppose it is this visibility that is causing the issue. You should not use api for common module if the app module is not using it. Common's visibility should only be exposed to the SDK module as its direct neighbour. You are right to not expose the common module as a transitive dependency of app module.
Trying being explicit about the class dependency:
public abstract class BaseConfiguration {
abstract var key: String?
abstract var token: String?
}
I would take a look at the compiled java class by the kotlin compiler and see how it generates it.
I'm using Dagger across several Gradle modules in an android project. I have a lib and app module. Inside lib module I have two classes PrivateThing and ExposedThing. ExposedThing depends on PrivateThing.
I have a dagger #Module to provide these two things:
#Module
public class LibModule {
#Provides
ExposedThing provideExposedThing(PrivateThing privateThing) {
return new ExposedThing(privateThing);
}
#Provides
PrivateThing providePrivateThing() {
return new PrivateThing();
}
}
In the app module, I have a single class SomeUiElement which depends on ExposedThing and a separate module:
#Module
public class ApplicationModule {
#Provides
SomeUiElement provideSomeUiElement(ExposedThing exposedThing) {
return new SomeUiElement(exposedThing);
}
}
And a component to bring everything together:
#Singleton
#Component(modules = {
ApplicationModule.class,
LibModule.class
})
public interface ApplicationComponent {
void inject(SomeActivity activity);
}
Now I want to enforce that nothing in the app module can depend on PrivateThing. I think I'm asking something similar to this question. One solution was to use component dependency. However the documentation recommends subcomponents see "Subcomponents for encapsulation".
Which is the preferred way to do this? Won't either method mean that lib module supplies it's own Component? I thought this was not a best practice, that libraries should only supply a Module.
I started working on a new Android project from scratch. After understanding the project scope and requested features, I've came up with a modular architecture (basically wrapping every feature into a feature or android module) that looks as following
Everything looks perfect until I wanted to introduce dagger to glue all the modules. The problem is that I want every module to has its own dagger component/subcomponent and it's modules in order to provide dependencies and expose them the graph to be using by other component or the parent one.
Google official dagger documentation states that subcomponents has direct access to parent component dependencies' and not vice versa. However, in my case the base component require dependencies from the data module and this latter itself require dependencies from the network module.
is there any solution for this problem knowing that i want every android module to have its own sub-component preferably? If not, is there any solution anyway?
Thank you.
Edit:
Here is how my project structure looks like
And this is how I setup my dagger graph
My AppComponent(Dagger root)
#Singleton
#Component(modules = {
AppModule.class,
ActivityBuilder.class,
AndroidSupportInjectionModule.class
})
public interface AppComponent {
void inject(CatApp application);
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
AppComponent build();
}
}
My App Module
#Module(subcomponents = DataComponent.class)
public class AppModule {
#Provides
#Singleton
Context provideContext(Application application) {
return application.getApplicationContext();
}
}
My DataComponent (located at the data android module)
#Subcomponent(modules = DataModule.class)
public interface DataComponent {
#Subcomponent.Builder
interface Builder {
DataComponent build();
}
}
Data module (located at data android module) that should provide the implementation of SystemManager
#Module(subcomponents = NetworkComponent.class)
public class DataModule {
#Provides
#Singleton
ISystemManager provideSystemManager(SystemManager systemManager) {
return systemManager;
}
}
Network Component (located at Network Android Module)
#Subcomponent(modules = NetworkModule.class)
public interface NetworkComponent {
#Subcomponent.Builder
interface Builder {
NetworkComponent build();
}
}
Network Module (located at Network Android Module) and should provide implementation of INetWorkManager
#Module
public class NetworkModule {
#Provides
#Singleton
INetworkManager provideNetworkManager(NetworkManager networkManager) {
return networkManager;
}
}
I am using #Inject annotation at all constructors so my configurations is all setup but the issue is that dagger doesn't compiles these subcomponent for some reason and I get this error when compiled:
Error:(27, 8) error: [dagger.android.AndroidInjector.inject(T)] com.github.andromedcodes.network.INetworkManager cannot be provided without an #Provides-annotated method.
com.github.andromedcodes.network.INetworkManager is injected at
com.github.andromedcodes.data.SystemManager.<init>(networkManager)
com.github.andromedcodes.data.SystemManager is injected at
com.github.andromedcodes.data.di.DataModule.provideSystemManager(systemManager)
com.github.andromedcodes.domain.managers.ISystemManager is injected at
com.github.andromedcodes.domain.interactors.CheckSystemAvailability.<init>(systemManager)
com.github.andromedcodes.domain.interactors.CheckSystemAvailability is injected at
com.github.andromedcodes.chasseautrsor.views.Splash.SplashPresenter.<init>(checkSystemAvailability)
com.github.andromedcodes.chasseautrsor.views.Splash.SplashPresenter is injected at
com.github.andromedcodes.chasseautrsor.di.SplashModule.bindSplashPresenter(presenter)
com.github.andromedcodes.chasseautrsor.views.Contract.Presenter is injected at
com.github.andromedcodes.mvp.BaseActivity.mPresenter
com.github.andromedcodes.chasseautrsor.views.SplashScreenActivity is injected at
dagger.android.AndroidInjector.inject(arg0)
How can I fix this issue knowing that I want to provide ISystemManager implementation at Data android Module and INetworkManager at Network Android Module?
Thank you.
Subcomponents automatically have access to objects bound in the parent components' graph, which makes sense, because subcomponents have exactly one parent component—there's no ambiguity. Parent components do not have automatic access to subcomponents' graph because you can create as many subcomponent instances as you'd like; it's not clear which instance you're trying to access. In general, unless you need different variations on an object graph (which you'd do with private modules or child injectors in Guice) or unless you wanted to hide implementation details (e.g. internal network objects), you may be better off installing your modules all in the same Component and skipping the subcomponent strategy.
However, if you do want to separate your graph or create multiple subcomponent instances, you could also create a subcomponent instance in a scoped #Provides method. That way NetworkComponent has a separate graph with private bindings, but can also use dependencies you expose in AppComponent, and you can also ensure that there is exactly one copy of NetworkComponent and its relevant bindings in your graph. You'll also need to put a getter (provision method or factory method) on the Subcomponent, so you can access some of its bindings from outside, in exactly the same way that you need a getter or injector method on a #Component for it to be useful.
#Subcomponent(modules = NetworkModule.class)
public interface NetworkComponent {
/** Allow anyone with a NetworkComponent instance to get the INetworkManager. */
INetworkManager getINetworkManager();
#Subcomponent.Builder
interface Builder {
NetworkComponent build();
}
}
/**
* Creates a singleton NetworkComponent. Install this in AppComponent's module,
* or in your data module if that encapsulates network calls.
*/
#Singleton #Provides NetworkComponent networkComponent(
NetworkComponent.Builder builder) {
return builder.build();
}
/** Make the INetworkManager accessible, but not the NetworkManager impl. */
#Provides static provideNetworkManager(NetworkComponent networkComponent) {
return networkComponent.getINetworkManager(); // add this to NetworkComponent
}
For further reference, see the "Subcomponents for Encapsulation" section on in the Dagger 2 docs on Subcomponents:
Another reason to use subcomponents is to encapsulate different parts of your application from each other. For example, if two services in your server (or two screens in your application) share some bindings, say those used for authentication and authorization, but each have other bindings that really have nothing to do with each other, it might make sense to create separate subcomponents for each service or screen, and to put the shared bindings into the parent component.
In the following example, the Database is provided within the #Singleton component, but all of its implementation details are encapsulated within the DatabaseComponent. Rest assured that no UI will have access to the DatabaseConnectionPool to schedule their own queries without going through the Database since that binding only exists in the subcomponent.
I'm having troubles trying to get my external Java project so I can use Android classes on it as well. The library is already integrated on the Android project. For instance: I have several model classes on it that I would want to implement Parcelable so they can be seriallized accordingly, but none of the Android classes are available on them.
Clarification I only did this in order to try to solve the issue
So far I've only tried:
Changing and matching the external library's package:
Package name in Android
com.domain.androidproject
Library's package originally
com.domain.libproject
Changed to:
com.dommain.androidproject.libproject
But no luck so far. I imported the library as a Gradle external project vĂa:
compile project(path: ':LibProject')
Thank you for your help.
You'll have to define a binding between your pure java library and android. You could use Dependency injection to inject the models using the class signature, and then define the parcelable models inside the app (or into another project, like a plugin). Or you could achieve the same using generics. keep in mind, since the java library is already compiled, technically, you can't change it by importing it into the android project (I've seen people "rewriting" some files from a dependency and then adding them with the whole original path to fool the classpath, but that's highly risky since you are not gonna be able to interact with the rest of the dependency's code and if something changes, the thing will break).
if you have access to the pure java's library sourcecode, then modify it to use factories or providers of models. If not, extend the models, add parcelable support, and attempt to use those instead of the original model classes.
Example:
let's suppose we have a model and some functions using it:
public class myModel{
private int id;
private String name;
public void setId(int id){
this.id = id;
}
//more getters and setters
}
public interface myModelCreator<T>{
public myModel create(T toModel);
public T uncreate(myModel fromModel);
}
public static void doSomething(myModel model){
//some library operations
}
Now, in the android project:
public class myAndroidModel extends myModel implements Parcelable{
/*Implements the parcelable methods using the class accessors, or you can change the myModel members to protected.*/
}
public class myAndroidModelCreator implements myModelCreator<myAndroidModel>{
#Override
public myModel create(myAndroidModel toModel){
//create the myModel using the parcelable class.
}
#Override
public myAndroidModel uncreate(myModel fromModel){
//reverse operation.
}
}
Now, in the android project, you can use the parcelable subclass everywhere, and everytime you need to call the library, you can supply the creator interface using the parcelables as arguments.
Another alternative would be changing the library method signatures to something like this:
public static void<T extends myModel> doSomething(T model){
//some library operations
}
So you can directly consume the parcelable subclasses. But depending on your hierarchy, that may be not possible. Lastly, you could attempt to implement dependency injection into the java project using Guice and Roboguice in the android project. Since roboguice uses guice, it is possible they can interoperate, but that's a long shot.
I like Fco P.'s answer, but for the sake of completness, here is an alternative answer.
Use json to serialize objects, rather than Parcelable. You can then put your serialized json as a string extra in intent or as string in bundles.
it's faster to implement than using Parcelable, with libraries such as Google GSON or Square moshi.
it's less performant than Parcelable
Generally if you want to make use of classes in another project/library:
File -> New -> Import Module -> Navigate to the directory of an old project/Library -> Ok
Check off the modules you want to import -> OK
Right click the app module -> Open Module Settings -> dependencies -> + -> Module -> The new Module.
Your project should then be usable in whatever project you just did that for.
Create an android library project with packagename com.domain.libproject
Copy all the sources in src folder.
Update jar dependencies in build.gradle and after that you can make your class in the library parcelable.
Let me know if any issues.
Best regds
GitHub Project Link
I have made a project on GitHub which is a model of the dagger 2 architecture of my projects actual architecture. This question will be based off of the GitHub project.
I have provided many code snippets in this question, however, it may be easier to just compile the project yourself in Android Studio to understand the problem.
If you check out the code, it won't compile. Go into AppModule.java and comment out both provides methods and it should compile.
The main question is the last line on this post.
https://github.com/qazimusab/Dagger2LibraryProject
Architecture
I have a library which contains all the code needed to make the application. The point of this architecture is that each app I create in the project should be able to use the library and ,through dagger 2, be able to provide different implementations for any single class or activity it wants in it's own module. At this point I only have one application in this sample project which uses the library.
The Problem
With dagger one, I had the same architecture, and in the app specific module (as opposed to the library module), I was able to add a new provides annotated method to override any implementation which was being provided in the any of the library modules as long as
The method was in a module in the app module
The method was annotated with #Provides
The method had the same return type as the one you want to override
With Dagger 2, the architecture works when I either don't override any provides or if I do, when I override every single provides in that module and remove that module from the includes from the Application specific module.
For example, in my project, I have an app and a library.
The app has an AppModule; the library has a CatModule to provide a Cat and CatFood, a dog module to provide a Dog and DogFood, and a LibraryModule to provide the activities.
CatModule.java
package com.example.qaziahmed.library.application.modules;
import com.example.qaziahmed.library.classes.Cat; import
com.example.qaziahmed.library.classes.CatFood; import
com.example.qaziahmed.library.classes.contract.ICat; import
com.example.qaziahmed.library.classes.contract.ICatFood;
import javax.inject.Singleton;
import dagger.Module; import dagger.Provides;
/** * Created by qaziahmed on 11/23/15. */ #Module public class
CatModule {
#Provides
#Singleton
ICat provideCat() {
return new Cat();
}
#Provides
ICatFood provideCatFood(){
return new CatFood();
} }
DogModule.java
package com.example.qaziahmed.library.application.modules;
import com.example.qaziahmed.library.classes.Dog; import
com.example.qaziahmed.library.classes.DogFood; import
com.example.qaziahmed.library.classes.contract.IDog; import
com.example.qaziahmed.library.classes.contract.IDogFood;
import javax.inject.Singleton;
import dagger.Module; import dagger.Provides;
/** * Created by qaziahmed on 11/23/15. */ #Module public class
DogModule {
#Provides
#Singleton
IDog provideDog() {
return new Dog();
}
#Provides
IDogFood provideDogFood(){
return new DogFood();
}
}
So, in my application module, I want to provide a house cat implementation of ICat instead of a generic cat and an AllNaturalDogFood implementation of IDogFood instead of just regular DogFood, then in my AppModule I add two provides to override those
AppModule.java
package com.example.qaziahmed.dagger2libraryproject.application;
import
com.example.qaziahmed.dagger2libraryproject.classes.AllNaturalDogFood;
import com.example.qaziahmed.dagger2libraryproject.classes.HouseCat;
import com.example.qaziahmed.library.application.modules.CatModule;
import com.example.qaziahmed.library.application.modules.DogModule;
import
com.example.qaziahmed.library.application.modules.LibraryModule;
import com.example.qaziahmed.library.classes.contract.ICat; import
com.example.qaziahmed.library.classes.contract.IDogFood;
import javax.inject.Singleton;
import dagger.Module; import dagger.Provides;
/** * Created by ogre on 2015-07-12 */ #Module(includes = {
LibraryModule.class,
DogModule.class,
CatModule.class }) public class AppModule {
#Provides
#Singleton
ICat provideHouseCat() {
return new HouseCat();
}
#Provides
IDogFood provideAllNaturalDogFood(){
return new AllNaturalDogFood();
} }
Now, when I run this setup, this is the error I get:
Error:com.example.qaziahmed.library.classes.contract.ICat is bound multiple times:
#Provides #Singleton com.example.qaziahmed.library.classes.contract.ICat com.example.qaziahmed.dagger2libraryproject.application.AppModule.provideHouseCat()
#Provides #Singleton com.example.qaziahmed.library.classes.contract.ICat com.example.qaziahmed.library.application.modules.CatModule.provideCat()
Error:com.example.qaziahmed.library.classes.contract.IDogFood is bound multiple times:
#Provides com.example.qaziahmed.library.classes.contract.IDogFood com.example.qaziahmed.dagger2libraryproject.application.AppModule.provideAllNaturalDogFood()
#Provides com.example.qaziahmed.library.classes.contract.IDogFood com.example.qaziahmed.library.application.modules.DogModule.provideDogFood()
Now, if in AppModule.java, I also add provides annotated methods to provide Cat Food and Provide Dog and then remove CatModule.class and DogModule.class from the includes in App Module then it works.
However, the whole question is how do I override a single provides method in some module in the library without having to override every provides annotated method inside that specific module and then removing that module from the includes in AppModule.java
Will try to decrypt this quote from the Dagger 2 docs:
Dagger 2 doesn't support overrides. Modules that override for simple testing fakes can create a subclass of the module to emulate that behavior. Modules that use overrides and rely on dependency injection should be decomposed so that the overridden modules are instead represented as a choice between two modules.
In your current example you don't rely on dependency injection because your provides* methods create simple new objects so you will be able to just create a subclass of the module, override the provides method that you need overridden and then include that new module in your component.
When you have reliance on DI (and in reality you will at some stage of your project) like this:
#Provides
#Singleton
ICat provideCat(IBowtie bowtie) { // 'bowtie' needs to be injected
return new CatWithBowtie(Bowtie);
}
it comes to "Modules that use overrides and rely on dependency injection should be decomposed" which basically means: you have to split CatModule in two: CatModule with just providesCat and 'CatFoodModule' with provideCatFood(). Then your app's component you just use your new CatWithBowtieModule instead of CatModule.
There two useful advises:
In library projects split modules so there is just one provides* method per module. Yes, it sounds like BS but this is the only way to provide easy overriding later in your app.
For a moment lets pretend that the library is given to you from a third party as a JAR/AAP and you don't even have the source. In that case you will not be able to reuse modules defined in the lib, so you will have to create all of them by yourself. This is exactly what happens with Dagger 2.
When you try to use modules from your lib in your app directly (as you did) these two projects are not two separate projects any more but one project that just looks like two projects (which are clusterf*ck tightly coupled). It is OK for the app to depend on the lib but it is not OK for the lib to depend on the app. It boils down to: In Dagger 2 it is best not to use cross (project) border modules and components.
Someone may ask: "What is the good of using Dagger 2 in a lib if I can't use lib's modules/components in my app?!". Well, you still will be able to use your dagger modules/components in your unit tests which is the main benefit of using Dagger after all. Also if your lib is meant to be used by other people you may (must?) provide a referent app which shows how to "wire" things so lib's users will be able to just copy that code if it suits them or at least see how to start.
The problem is that your Injection sees two methods that are providing the same object.
If you read this link: http://google.github.io/dagger/ you can remedies to that by naming your provider as:
#Provides #Named("water")
Then, in your Injection, reference it like:
#Inject #Named("water")
As a workaround , I write two methods, one for #Provides and one for #Overrides.
#Override
protected X getX() {
return new X();
}
#Provides
X provideX() {
return getX();
}