I created two modules in single android project.
app module(which is default my app module)
and another added library module.
Now app module have many java classes. i want to access .Java class of app module in library module.
Module app has a class DatabaseHelper in package xyz
Now I want to import class DatabaseHelper in Library module.
DatabaseHelper is not recognized by android.
Questions,
Is it possible to import Class from a app module to another module?
any other way.
MyFiles
build.gradle(app)
compile project(':materialList')
setting.gradle
include ':app', ':Library'
Is it possible to import Class from a app module to another module?
This won't be possible as this will be creating a circular dependency.
However there is a pattern that can be utilized in this scenario:
Define the data type : DatabaseHelperContent in the library module
Define an interface DatabaseHelperI in the library module the implementer of which is supposed to provide the data.
Create a DatabaseHelperImpl class implementing the DatabaseHelperI interface, providing the data (this class is in the app module)
Initialize the interface as the instance of class ABC while referring to it in the Application class, so that the data from the class can be dynamically passed to the sub-module.
This would become even simpler with some dependency-injection framework
like Dagger where you can just specify provider of the interface in
the #Module class and use the injected data from the common provider everywhere.
No, there is no way. Rethink your design. Maybe move DatabaseHelper into library project?
In your design, there would be a circular dependency between app module and library module.
The purpose on other modules is to separate completely independent pieces of code and move them to external place. And use them in another modules.
It's quite an old question and I am sure the author has found a solution, but I think the question lacks this answer which many people would like to know.
So, actually, as suggested in other answers, this often might be caused by an issue with your architecture.
But sometimes it may be reasonable. For instance, if you need to access your application id inside a library or in many other cases.
So, if you need to access a resource from the app module in a library module,
it can easily be done with help of dependency injection.
For instance, with Dagger it can be done like this:
1.Create a module that will provide a shared resource.
Let's call it the Integration module.
#Module()
class IntegrationModule {
#Provides
#Named("foo")
fun provideFoo() = "Hey bro"
}
2.Include it in your App component
#Component(modules = [
AndroidSupportInjectionModule::class,
AppModule::class,
IntegrationModule::class,
YourLibraryModule::class
])
#Singleton
interface AppComponent : AndroidInjector<App> {
#Component.Builder
interface Builder {
#BindsInstance
fun app(app: Application): Builder
#BindsInstance
fun context(context: Context): Builder
fun build(): AppComponent
}
}
3.Inject it somewhere in your library
#Inject #Named("foo") lateinit var foo: String
That's it.
Base Dagger implementation code is omitted for simplicity.
Related
I'm using Koin 3.2 which has the new module includes feature. In the official docs, when discussing module linking strategies, there is this paragraph:
An important detail to observe is that you can use includes to add internal and private modules too - that gives you flexibility over what to expose in a modularized project.
That is exactly what I need, but I can't find elsewhere in the docs how to set up a "private" module that only provides dependencies for the parent module, so that those child dependencies are not available for injection. E.g.:
class SomeNonInjectableClass
class SomeInjectableClass(private val sni : SomeNonInjectableClass)
val privateModule = module {
singleOf(::SomeNonInjectableClass)
}
val publicModule = module {
includes(privateModule)
singleOf(::SomeInjectableClass)
}
In my main app I list the public module only, but automatically Koin provides all the included modules:
startKoin{
androidLogger()
androidContext(this#Main)
modules(publicModule)
}
So now a developer can do this from any activity:
val foo : SomeInjectableClass by inject() //Ok
val bar : SomeNonInjectableClass by inject() //I don't want this
I want developers to not to be able to inject the non-injectable classes from the private module. Something like Dagger 2's #NonInjectable marker qualifiers.
Is this possible or should I resort to manually building my definitions using the classic DSL?
From what I've understood, this new includes feature simply makes possible to have the whole module definition private or internal, not allowing you to include them to modules outside this scope. I guess it has more to do with controlling the creation of Koin modules in large modularized projects than to be able to control what the developer can or cannot inject.
private val privateModule = module {
singleOf(::SomeNonInjectableClass)
}
I can understand how making this private to its scope can avoid some confusions when creating large compositions of koin modules across different kotlin modules (especially it there are a lot of definitions inside the private module) but at the same time I'm also frustrated that it seems it is not possible to achieve what you want to do.
To clarify: includes operator allow to load other modules with the given module.
If you want to avoid to share internal implementation, check your Gradle module exposure. For example, just share interfaces.
I am working on an e-commerce site. I am following clean architecture with MVVM and Dagger 2.But am getting stuck when we need to communicate in between modules, means i have to call some methods and class from one module another.
Actual scenario is - There is one separate module for cart and another for categories(consisting of products based on categories)
I have some set of APIs in cart module (ex. addToCart,fetch cartList,remove cart item etc.)which need to be call in both cart module and categories module(addToCart API need to call from categories module).
One way to do it as again writing same code in both module that will increase extra effort and also make both module dependent,thats violate clean architecture approach.
Can anybody suggest me best approach for this in clean architecture.
You can create a new module with the shared code and add it as dependency in both modules (cart and categories), if you have modularized by layers you can do the same for data layers, so if you need the same APIs in another module you can add it as dependency or split it in new modules if you will use only some parts.
implementation project(':common_apis_module')
In clean architecture if you do a request from a module it's understood as different usecases, if you need to get the same data from the model in both cases maybe you need share the UseCase as well in a common module.
Create Interfaces for communication between modules in common_apis_module.
interface CommunicationModule1 {
fun doSomethingInModule1(someParam: String)
fun doAnotherThingInModule1(anotherParam: Int)
}
and create another interface for communication in second module equal as above.
then you have that common module added in both modules you'll be able to use the interfaces in both modules.
I recommend use dagger.
class OneClassInModule2 : DaggerAppCompatActivity{
#Inject
late init var communicationModule1 : CommunicationModule1
}
Second Class:
class OneClassInModule1: CommunicationModule1 {
override fun doSomethingInModule1(someParam: String){
// Do Something with the string
}
}
So I am currently in the process of learning dagger 2, and from the tutorials that I've read so far, for a dependency to be injected, the #Inject annotation gets placed inline with fields (for Activities/Fragments) or constructors. However I see that as an issue if I'm not the owner of parts of the code and can't add the required annotations for this technique to work, or if I don't want other parts of the code to know that dagger exists.
The application structure I have at the moment is:
App Module - where I'd like to put my DI code in (e.g. dagger modules, etc).
Presentation Module - Views/ViewModels etc.
Domain Module - Use Cases etc.
Data Module - Repositories etc.
With pretty much this style of classes contained in my application:
class ExampleViewModelImpl(useCase: ExampleUseCase): ViewModel() in Presentation (gets initialised from an Activity or similar).
class ExampleUseCaseImpl(repository: ExampleRepository): ExampleUseCase in Domain
class ExampleRepositoryImpl(dao: ExampleDao): ExampleRepository in Data
With the structure above, what is the minimum number of classes outside of the App Module that I need to touch in order to utilize dagger with as much automated dependency injection as possible? Code examples of how this is achieved would be great.
I am unsure of some terminologies, and wasn't able to find a solution online. If there are good resources which explains what I'm asking, that would also be great.
if I don't want other parts of the code to know that dagger exists.
#Inject is a standard (JSR 330) which Dagger implements. Adding those annotations doesn't have anything to do with Dagger and can be used the same way with other DI frameworks. If it's your code you should just add those #Inject annotations where appropriate. Think of them as documentation: What constructor/field/method must be injected to create & use this object?
The only place where your classes will know that Dagger exists is at the same place where you'd be creating the objects otherwise, too.
Going down that path, of course you could use Dagger without any #Inject annotations, but you'd be writing a lot of unnecessary boilerplate and missing out on the most powerful feature of Dagger at the same time (code generation).
#Inject annotation gets placed inline with fields (for Activities/Fragments) or constructors. However I see that as an issue if I'm not the owner of parts of the code and can't add the required annotations for this technique to work
That's what #BindsInstance with the #Component.Builder is for (add an object to the component) and what #Provides annotated methods are for (create and initialize an object from a module)
If you really want to write code without #Inject, then you'd do exactly this for all of your objects. This means a lot of modules, and even more #Provides annotated methods. It will work, but I don't see the point in writing all those methods if a single #Inject on the constructor has the same effect.
In my opinion the best thing about Dagger is that I can add / remove / change constructor parameters and don't have to touch any other parts of my code since Dagger will generate new code with the new arguments. In your case you'd have to also change the parameters to the #Provides method as well as the constructor invocation.
Next let's look at how to remove #Inject from fields. Basically you don't want to do field injection, so instead of writing an injection method in the component, you'd write provision methods.
#Component
class MyComponent {
fun inject(activity: MyActivity)
}
class MyActivity {
#Inject lateinit var myDep: Dependency
fun onCreate() {
component.inject(this)
}
}
Removing the #Inject we need to use the provision methods instead.
#Component
class MyComponent {
fun provisionMyDependency() : Dependency
}
class MyActivity {
lateinit var myDep: Dependency
fun onCreate() {
myDep = component.provisionMyDependency()
}
}
It will work and everything, but again, you will miss out on the single best feature of Dagger: Code generation. The example above looks alright because I only added a single dependency, but think about what happens to those 2 different implementations when you add / remove / change dependencies, how well it will scale. If you prefer to do things manually any refactoring will become arduous.
With the structure above, what is the minimum number of classes outside of the App Module that I need to touch in order to utilize dagger with as much automated dependency injection as possible?
Your question (especially the title) is in direct conflict with your goal. If you don't want to use those annotations, then you can't use Dagger code generation & injection but have to resort to do it manually as highlighted above.
with as much automated dependency injection as possible
To best utilize Dagger you add #Inject on the constructor and/or fields of every class that should end up on your dependency graph and let Dagger do its thing.
Note: There seems to be a number of questions about the similar issue but this one is more specific to multi-module app and previously suggested solutions do not work
I'm starting a multi-module project with one module (Android studio module) for each architectural layer (i.e., Data, Domain, Presentation) and using Dagger 2 to provide dependency injection across the app. Currently I have one Dagger Component for each module which exposes dependencies from each module to other modules. A simplified version looks like this:
#Singleton
#Component(modules=[DataModule::class])
DataComponent {
fun tokenRepository(): TokenRepository
fun jobRepository(): JobRepository
}
#Singleton
#Component(modules=[DomainModule::class])
DomainComponent {
fun somethingSingleton(): Something
}
// In Presentation Module
#PerApp
#Component(dependencies = [DataComponent::class, DomainComponent::class])
AppComponent {
fun tokenRepository(): TokenRepository
fun jobRepository(): JobRepository
fun somethingSingleton(): Something
}
I got an error saying Dagger component is not allowed to depend on multiple scoped components. However since both Data and Domain components need to provide singletons (like token repository), I have to use something like #Singleton #Provide fun getTokenRepository... in DataModule which requires DataComponent to be also scoped.
I've tried to avoid component dependencies by not creating DataComponent and DomainComponent and instead having AppComponent referencing DataModule and DomainModule like below.
#PerApp
#Component(modules = [DataModule::class, DomainModule::class])
AppComponent {
fun tokenRepository(): TokenRepository
fun jobRepository(): JobRepository
fun somethingSingleton(): Something
}
However that does not work unless Presentation module declares (gradle) dependencies for data-related libraries like database or caching library which are used to implement the repository. I feel that would ruin the idea of modulization since those dependencies should not be a concern of the Presentation layer.
I was wondering if any one had the same issue before and how did you resolve it?
Thanks
Fellow Dagger users...am I trying to do something impossible? Below is a degraph generated Gradle module view of my app.
Imagine my app has a navigation drawer. I want the list items in the drawer to be added based on a collection populated via a multibinding. The contributors to this multibinding are across > 1 Gradle module.
For example, a list item called "Account" is added from the user module, a 2nd item called "Terms & Conditions" is added from the legal module and a "Search" navigation entry is added from the search Gradle module. These modules can be thought of as stand-alone apps that when bundled together form the complete app experience. They are runnable on their own.
The Dagger documentation on this looks like a copy-paste of the Guice but with one big complication. It states;
"Dagger allows you to bind several objects into a collection even when
the objects are bound in different modules using multibindings. "
...but it means Dagger #Modules, right? Is it possible to populate a multibinding across Gradle modules? I've tried something akin to this and it wasn't what I expected (not all contributions were collected);
Parent app
#Module
abstract class PluginModule {
#Multibinds #NavigationContribution abstract Set<NavigationEntry> navigables();
}
legal Gradle module that contains the Dagger #Module
#Module
class LegalModule {
#Provides
#NavigationContribution
#IntoSet
static NavigationEntry provideLegalNavigation() {
return ...;
}
}
user Gradle module that contains the Dagger #Module
#Module
class AccountModule {
#Provides
#NavigationContribution
#IntoSet
static NavigationEntry provideAccountNavigation() {
return ...;
}
}
Upon running the app only the contributions under the app 'context' are available upon calling;
#Inject #NavigationContribution Set<NavigationEntry> navigationEntries();
The other contributions can be accessed but 'manually' by getting hold of the dagger.Component of the child Gradle module and exposing a method to get the entries back.
This defeats the purpose of the multibinder for my application. Is this possible? If not, why?
Update: triage with Jeff
So, the top-level module annotations look like this;
#ApplicationLifecycle
#Component(
modules = {
OceanLifeModule.class,
AddSpotActivityModule.class,
ModelModule.class,
PluginModule.class
},
dependencies = {
NavigationComponent.class,
LegalComponent.class,
PreferenceComponent.class,
DomainComponent.class
}
)
#jeff-bowman - all I was missing here was the includes = {} on the PluginModule. A blog post by Zac Sweers on the same topic here pointed me in the right direction.