How to pass an interface as parameter in koin - android

I'm so beginner in koin.
I have a method that named "MesheRepoImpl" that get an interface as parameter.
I know that I can't pass an interface to a method in Koin, so I created a class and extends that from the interface then I added that class in koin module, so I use the class as parameter for MesheRepoImpl.
But android studio gives me this error:
Caused by: org.koin.core.error.NoBeanDefFoundException: |- No definition found for class:'com.app.meshe.data.repo.MesheRepo'. Check your definitions!
This is my Di module:
val mesheModule =
module {
single { getInstance(androidContext()) }
single { MesheLocalDataSource() } //*
single { MesheRepoImpl(get()) } //**
factory { TaskViewModelFactory(get()) }
viewModel { TaskViewModel(get()) }
viewModel { RewardViewModel(get()) }
viewModel {MainViewModel()}
}
The 1 star line is my class that extends from the interface and the 2 stars line is the class that get interface as parameter.
How can I pass the interface as parameter, if I can't use a class?

Since there's still no answer, I'd advise you to consider going with
interface MesheRepo
class MeshoRepoImpl(): MeshoRepo
over your
interface MesheRepo
class MeshoRepoImpl(val IRepo: MeshoRepo)
So, just implement MeshoRepo over passing it as an argument to MeshoRepoImpl.
Trying to answer directly your question, you are able to define interfaces in Koin module and pass them, but you have to provide their implementations, as well:
val mesheModule = module {
single<MeshoRepo> { MeshoRepoImpl() }
single { MeshoRepoImpl(get()) } // <-- it's like a deadlock, so I still do not see any sense to pass an interface over implementing it
}
And, please, do not forget that an interface is not an object.

Related

How to scope a Usecase to a Feature / Activity in Koin

I'm maintaining a large app (mostly) using a "one feature one activity"-architecture.
Now i'd like to scope a usecase, so it lives as long as the activity, something like this:
// koin module
scope<MyFeatureActivity> {
viewModel { MyFeatureActivityViewModel() }
viewModel { MyFeatureFragmentAViewModel(usecase = get()) }
viewModel { MyFeatureFragmentBViewModel(usecase = get()) }
scoped { MyFeatureUseCase() }
}
// fragments
class FeatureAFragment: AppCompatDialogFragment(){
private val viewModel by viewModel<MyFeatureFragmentAViewModel>()
....
}
// activity
class MyFeatureActivity : ScopeActivity() { ... }
However, this doesn't work. When launching MyFeatureFragmentA from MyFeatureActivity it's throwing an Exception:
org.koin.core.error.NoBeanDefFoundException:
|- No definition found for class:'MyFeatureAViewModel'. Check your definitions!
What am i doing wrong?
Please note: I would not like to just skip scopes and make the usecase a single (or a factory), since it actually stores some data relevant to only this activity: The data should be kept while we're in this feature, but dismissed when leaving it.

Dagger2 dependency injection: How does it work in an android app?

I am trying to understand an example for an app with offline support using retrofit and room:
You can find the code for it here:
This project is using dependency injections with Dagger2. I've never worked with it so I am trying to understand how things work together. I understand the purpose of dependency injection but I don't understand the implementation of the project above.
I found a very good introduction into Dagger2 here:
A Friendly Introduction to Dagger 2
Dagger 2 example Code:
I worked through it and got most of it. Back to the actual project I am trying to understand (link 2). It still doesn't make sense to me and here is why:
The interface AppComponent has one method which is used:
public void inject(MainActivity2ViewModel viewModelModule); The return type is void. In the Dagger2 sample project (link 3 and 4) they use WeatherReporter getWeatherReporter(); which makes sense because later they call this method to get a WeatherReporter-Instance and Dagger2 manages all of the instantation process in the background. But I get nothing if the return type is void. Why is the return type not an object?
There is one #Inject in MainActivity2ViewModel:
#Inject
public void setRepository(GitHubRepository2 repository) {
this.repository = repository;
}
repository is the only field of MainActivity2ViewModel so it is a dependency. The GitHubRepository2 constructor has 3 parameters:
#Inject
public GitHubRepository2(GitHubApi api, GitHubDao dao, Executor executor)
For each of them there is a module explaining how to create those objects. But why is there an AppModule and a NetModule? Maybe the AppModule is there because DaoModule needs an Application reference but why is there a NetModule and where is it used?
There's a lot of comprehensive tutorials about Dagger2 in Android. But I'll show you a glimpse of what it's used for. And minimal usage.
Ultimately, dagger will use the annotation #Inject which will provide(reference to the object or value) to the variable.
Injection is usually used on reusable or boilerplate objects like Dao, Repository, ViewModel, NetworkAdapter
class SomethingThatRequiresNetwork { // Activity, Fragment
#Inject
MyReusableNetworkAdapter myReusableNetworkAdapter;
String baseUrl; // for example purpose only
SomeDependency someDependency;
void init() {
// #NOTE: DaggerMyExampleComponent is a generated class. It will be red before compilation.
MyExampleComponent MyExampleComponent = DaggerMyExampleComponent.builder().build();
MyExampleComponent.inject(this); // the actual injection happens here
}
// yes, you can just use #Inject on the variables directly but this is another use.
#Inject
void methodInjection(String baseUrl, SomeDependency someDependency) {
this.baseUrl = baseUrl;
this.someDependency = someDependency;
}
}
// ANSWER to the two questions
// this is a pseudocode of the generated code. You do not write this
// MyExampleComponent class
void inject(SomethingThatRequiresNetwork obj) {
// #NOTE: modules are actually instantiated by MyExampleComponent. Not called statically. I just shortened it
obj.myReusableNetworkAdapter = NetModule.provideNetworkAdapter();
obj.methodInjection(NetModule.provideBaseUrl(), SomeModule.provideSomeDependency());
}
// these here are modules that provide by return TYPE
// you write these
#Module
class NetModule {
#Provides
#Singleton
String provideBaseUrl() {
return "www.some-url.com";
}
#Provides
#Singleton // will store the object and reuse it.
// #NOTE: provision can work internally within modules or inter-module. the input here is provided by provideBaseUrl
MyReusableNetworkAdapter provideNetworkAdapter(String baseUrl) {
return new MyReusableNetworkAdapter(baseUrl);
}
}
#Modules
class SomeModule {
#Provides
#Singleton
SomeDependency provideSomeDependency() {
return new SomeDependency();
}
}
// Component. uses modules
#Singleton // .build() will reuse
#Component(modules = {NetModule.class, SomeModule.class})
interface MyExampleComponent {
// the method name doesn't matter
// the class type does matter though.
void inject(SomethingThatRequiresNetwork somethingThatRequiresNetwork);
// some other class that needs injection. #NOTE: I did not give example for this
void inject(SomethingThatRequiresDependency some);
}
NOTE. This code is usually written from bottom to top lol. You start writing the Component then Module then Injections.
Just follow the calls from the top of this answer and you'll figure out how Dagger2 works.

Can injecting a field member with Dagger be done with only a constructor

I inject a field member as follows:
#Inject
lateinit var repository: Repository
What I have noticed is that repository will only get set if I use a component builder:
init {
DaggerLoginViewModelComponent
.builder()
.build()
.inject(this)
}
But I have read in several places that the field member will get set even if you just mark the constructor of the class you want instantiated with Inject:
class Repository #Inject constructor() {
}
But I have not found this to be true. Even with the constructor having the Inject annotation present, I still need to run the builder. Can someone confirm whether this is true or not.
The way field injections work is through a supplemental method on the Dagger component, in this case inject(this).
If you look at the Dagger generated code, you'll see that inject() method's body contains the code to perform the member injection.
Here's how the generated code would look-
#Override
public void inject(Foo instance) {
injectFoo(instance);
}
private injectFoo(Foo instance) {
Foo_MembersInjector.injectRepository(instance, repositoryProvider.get());
return instance;
}
...
public final class Foo_MembersInjector implements MemberInjector<Foo> {
public static void injectRepository(Foo instance, Repository repository) {
instance.repository = repository // <-- this is where the actual injection happens
}
}
You're right when you say that Dagger knows how to construct the Repository object, but it doesn't know that this object has to be injected in a separate class. And that only happens when you call the inject() method with the instance of specific type, which is how it generates code to perform the injection.
Hope this helps.

How to provide parameter to constructor while doing constructor injection?

I am using dagger2 framework for dependency injection.
How to create instance of dependency objectB (AND INJECT) with a constructor injection. Class B has a parameter constructor.
Please find the example below.
//This is class A, which is dependent on Class B.
//This has to create instance of B, with a (int) parameter.
class A {
#Inject
public B objectB;
public A(int some_value){
//This one I want to make it through dagger2
//objectB = new B(some_value);
BComponent bComponent = DaggerBComponent.builder().build();
bComponent.provideB(this);
}
}
//This is Class B, which has constructor injection.
//Constructor has a int parameter.
class B {
#Inject
public B(int var){
other_method(var);
}
}
//This is dagger module, which provides Object B
#Module
public class BProvider {
#Provides
public B getB() {
return new B();
}
}
//This is dagger component, provide class-B dependency to class-A
#Component(modules = {BProvider.class})
public interface BComponent {
void provideB(A objA);
}
From the elaboration in the comments:
I am trying constructor injection to achieve dependency. ClassA depends on ClassB. And ClassB has parameter constructor, say ClassB(int param). This parameter is provided at runtime, so my confusion is how dagger is able to create object B.
If B's param is the same every time, across your object graph
This might be the case if your param is a key, ID, or other configuration setting. If so, you can use a #Provides method in a Module to teach Dagger how to provide a ClassB object when you ask for one.
#Module
public abstract class YourModule {
#Provides static ClassB provideClassB() {
return new ClassB(/* your constant here */);
}
}
Because #Provides methods can take parameters that come from the object graph, you can even get your value from somewhere else:
#Module
public abstract class YourModule {
#Provides static ClassB provideClassB(SomeDependendency someDep) {
return new ClassB(someDep.getParameterForClassB());
}
}
If B only takes custom parameters
This might be the case if your ClassB is a data object or disposable object, especially if you don't need to replace ClassB for testing. (Don't mock data objects.) If all of that is true, then ClassB doesn't need to be a part of your object graph. Call the constructor directly.
ClassB myB = new ClassB(someParameter);
Sometimes this distinction is called injectables versus newables: If you have complicated and interconnected classes that need to access one another, you have an injectable, and references to it should be provided externally. If you have a tightly-contained class that doesn't need substitution, you have a newable, and can call the constructor or static factory method directly.
If B has injected parameters AND constructor parameters
In some cases, a class like ClassB needs both one-off constructor parameters and injected parameters from the graph at the same time. Though this might be a subtle hint that the class is doing too much, there are common workarounds that combine those two inputs into the same list of constructor parameters. This is known as assisted injection, and allows for the creation of factory objects where the DI framework provides the factory and you use it to get the value you want.
/* in ClassB */ public ClassB(DepA a, DepB b, int param) { /* ... */ }
/* ClassBFactory */
public ClassBFactory {
Provider<DepA> depAProvider;
Provider<DepB> depBProvider;
public ClassBFactory(
Provider<DepA> depAProvider,
Provider<DepB> depBProvider) {
/* set depAProvider and depBProvider */
}
public ClassB get(int param) {
return new ClassB(depAProvider.get(), depBProvider.get(), param);
}
}
Because this is similar boilerplate-generation to Dagger, but more reusable in other dependency injection frameworks, Dagger recommends the Google project AutoFactory to generate that implementation based on inspecting the dependencies and classes. You'll need to add some annotations to ClassB to get that to work, but it will allow you to distinguish between graph-provided deps and one-off deps, and insulate you from having to change constructor calls if your dep list changes.

What should go in the "injects" in a Dagger #Module?

Guice user, trying to understand a bit of the benefits of Dagger here.
Let's say I have the following
MyActivity.java
---------------
public class MyActivity {
#Inject MyImplicitClass myImplicitClass;
#Inject #Named("foo") MyExplicitClass myNamedExplicitClass;
...
}
MyImplicitClass.java
------------
public class MyImplicitClass {
#Inject
MyImplicitClass(MyExplicitClass myExplicitClass) {
...
}
...
}
MyModule.java
---------------
#Module(injects = { ? }) {
#Provides provideExplicitClass() {
return new MyExplicitClass();
}
#Named("foo") #Provides provideNamedExplicitClass() {
return new MyExplicitClass();
}
}
So, my question is, what should go in the Injects?
I know for a fact that MyActivity needs to go. Or rather, whatever "this" needs to have DaggerInjector.inject(this)
Does anything else?
Would Dagger the implicit construction injection class (MyImplicitClass) and/or the class explicitly provided in the module (MyExplicitClass) to also be specified?
MyExplicitClass wouldn't even make sense if I need it to be annotated.
However, the javadoc makes me feel I should error the side of inclusion
http://square.github.io/dagger/javadoc/dagger/Module.html#injects()
Dagger 1 does it's validation at compile therefore it needs all of the entry point you're going to use at runtime (objectgraph.get(entrypoint), objectgraph.inject(entrypoint)).
Entry points are the injectable classes which are at the top of the dependency graph. In Android most of the time those are your Activities, Fragments, Services, Broadcast Receivers. All compontents which are not created by Dagger. You would also list classes which are not part of any entry point's dependency tree again becoming an entry point of their own.
Those entry point are use to do validation by Dagger. Dagger will start validation at the entry points and tricle down the dependency tree and validate dependencies annotated with #Inject and #Provides from your Modules.
So in conclusion only entry points needs to be provided in the #Module(injects = { * })
In your example because the MyImplicitClass is an #Inject dependency of your entry point MyActivity you don't need to specify it in the #Modules(injects={}). The same is true for your MyExplicitClass dependency. Therefore from your example the only class that needs to be added to the list is in fact MyActivity.
Base on your example code, if you had something like this.
// MyIndependantClass.java
-----------------
public class MyIndependantClass {
#Inject
MyIndependantClass(MyExplicitClass myExplicitClass) {
}
}
// MyActivity.java
---------------
public class MyActivity {
#Inject MyImplicitClass myImplicitClass;
#Inject #Named("foo") MyExplicitClass myNamedExplicitClass;
...
protected void onCreate (Bundle savedInstanceState) {
MyIndependantClass myIndependantClass = MyObjectGraph.get(MyIndependantClass.class);
...
}
}
The fact that MyIndependantClass is created using ObjectGraph.get() and is not a direct dependency of your MyActivity entry point you would need to declare that class part of the injects list.
// MyModule.java
---------------
#Module(injects = { MyActivity.class, MyIndependantClass.class }) {
#Provides provideExplicitClass() {
return new MyExplicitClass();
}
#Named("foo") #Provides provideNamedExplicitClass() {
return new MyExplicitClass();
}
}

Categories

Resources