I think the easiest way to explain is with a code example that includes RxJava
class SomeClass {
CompositeSubscriptions subscriptions;
public SomeClass(CompositeSubscription subscriptions) {
this.subscriptions = subscriptions;
subscriptions.add(...);
subscriptions.add(...);
subscriptions.add(...);
subscriptions.add(...);
subscriptions.add(...);
}
public void destory() {
subscriptions.unsubscribe();
}
}
So what I want to be able to do is to have classes just be able to ask for a CompositeSubscription and they get the one for there scope. That way they can freely unsubscribe the whole CompositeSubscription. This would be needed so that my Singletons don't interfere with my Activities which don't interfere with my Fragments.
You cannot have the same class provided in multiple scopes. You get an error {Class} is bound multiple times.
So the following setup is not valid
#Module
public class ActivityRxJavaModule {
#Provides
#PerActivity
CompositeSubscription providesCompositeSubscription() {
return new CompositeSubscription();
}
}
#Module
public class FragmentRxJavaModule {
#Provides
#PerFragment
CompositeSubscription providesCompositeSubscription() {
return new CompositeSubscription();
}
}
So there are two solutions that I know of.
Subclass per scope
a. Singleton{Class}, PerWhatever{Class}
Using the name annotation
a. #Named("singleton"), #Named("perwhatever")
I seem to prefer the Subclass per scope because I feel like it is a bit safer when refactoring, but both should work.
Related
I learn how to test the presenter layer of MVP architecture in android, my presenter using retrofit 2 and in my activity I used dagger 2 as dependency injection to my presenter, this is my Dagger and presenter injection looks like:
#Inject
AddScreenPresenter addScreenPresenter;
This is the Dagger builder :
DaggerAddScreenComponent.builder()
.netComponent(((App) getApplicationContext()).getNetComponent())
.addScreenModule(new AddScreenModule(this, new ContactDatabaseHelper(this)))
.build().inject(this);
and this is my presenter constructor :
#Inject
public AddScreenPresenter(Retrofit retrofit, AddScreenContact.View view, ContactDatabaseHelper contactDatabaseHelper)
{
this.retrofit = retrofit;
this.view = view;
this.contactDatabaseHelper = contactDatabaseHelper;
}
I have write the unit test class and mock the Retrofit class, but when I run it, the error appears :
Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types
This is the test class :
#RunWith(MockitoJUnitRunner.class)
public class AddScreenPresenterTest {
private AddScreenPresenter mAddPresenter;
#Mock
private Retrofit mRetrofit;
#Mock
private Context mContext;
#Mock
private AddScreenContact.View mView;
#Mock
private ContactDatabaseHelper mContactDatabaseHelper;
String firstName, phoneNumber;
Upload upload;
#Before
public void setup() {
mAddPresenter = new AddScreenPresenter(mRetrofit, mView, mContactDatabaseHelper);
firstName = "aFirstName";
phoneNumber = "998012341234";
Uri path = Uri.parse("android.resource://"+BuildConfig.APPLICATION_ID+"/" + R.drawable.missing);
upload = new Upload();
upload.title = firstName;
upload.description = "aDescription";
upload.albumId = "XXXXX";
upload.image = new File(path.getPath());
}
#Test
public void checkValidationTest() {
verify(mAddPresenter).checkValidation(firstName, phoneNumber);
}
#Test
public void uploadMultiPartTest() {
verify(mAddPresenter).uploadMultiPart(upload);
}
}
this is my module :
#Module
public class AddScreenModule {
private final AddScreenContact.View mView;
private final ContactDatabaseHelper mContactDatabaseHelper;
public AddScreenModule (AddScreenContact.View view, ContactDatabaseHelper contactDatabaseHelper)
{
this.mView = view;
this.mContactDatabaseHelper = contactDatabaseHelper;
}
#Provides
#CustomScope
AddScreenContact.View providesAddScreenContactView() {
return mView;
}
#Provides
#CustomScope
ContactDatabaseHelper providesContactDatabaseHelper() {
return mContactDatabaseHelper;
}
}
I know that Retrofit class is a final class, and now I stuck and don't know how to create the presenter object in my test class. Please help me, how to create the object of the presenter class with retrofit in the constructor. Feel free to ask if my question is not clear enough, and thank you very much for your help.
Personally I'd make the presenter not depend on the Retrofit class but rather on the services created by Retrofit - These are mockable.
It's hard to say from the code you posted which services your presenter actually uses, but for the sake of simplicity let's say it uses only one and let's say it's AddsService - This is an interface ready to work with Retrofit. Something like this for example
public interface AddsService {
#GET(...)
Call<List<Adds>> getAllAdds();
}
Now you can make your presenter depend on this rather than Retrofit
#Inject
public AddScreenPresenter(AddsService addsService,
AddScreenContact.View view,
ContactDatabaseHelper contactDatabaseHelper){
this.addsService = addsService;
this.view = view;
this.contactDatabaseHelper = contactDatabaseHelper;
}
You now need to provide this dependency. I'm guessing you have also a NetModule since you have a NetComponent, so I assume you can just do:
#Module
public class NetModule {
// Methods providing Retrofit
#Provides
#Singleton
public AddsService providesAddsService(Retrofit retrofit) {
return retrofit.create(AddsService.class);
}
}
Notice how the providesAddsService depends on retrofit? This should be already provided since your presenter is depending on it. You shouldn't need to change anything for that. Dagger is able to figure out how to provide Retrofit to the method providesAddsService.
Please notice also that I'm assuming you can provide these in a Singleton scope. I assume this because in your code you retrieve the component from the application, which should handle the singleton scope.
Now in your tests you can simply mock AddsService and test your presenter.
If your presenter depends on more services, I'd also pass them in the constructor and provide the implementations with Dagger.
As a bonus, let me also say that the retrofit instance and the retrofit services should only be created once (or at least as less times as possible). This is because they're usually expensive operations and you usually always query the same endpoints with different parameters.
EDIT
To answer some of the questions in the comments. First the easy one: How to create the presenter in the test classes? Like you I too try to get away from Dagger during tests, that's why I prefer constructor dependency injection just like you show you're using. So in my test class I'd have something very similar like you:
#RunWith(MockitoJUnitRunner.class)
public class AddScreenPresenterTest {
private AddScreenPresenter mAddPresenter;
#Mock
private AddsService addsService;
// ...
#Before
public void setUp() throws Exception {
mAddPresenter = new AddScreenPresenter(addsService,
mView, mContactDatabaseHelper);
// ...
}
}
So basically the only difference is that I would pass the mock to the service.
Now the second question: How to call the presenter constructor from the activity? Well you don't... that's the whole idea of dependency injection. You should use dagger to provide your presenter. I think this is already what you do and I guess this is what it's in your activity:
#Inject
AddScreenPresenter addScreenPresenter;
So all you need to do is have a provider method in your module that provides this and is able to inject it.
You can also make the component return the presenter provided by the module:
#Component(...)
public interface AddScreenComponent {
AddScreenPresenter getPresenter();
}
And then in your activity you'd do something like:
addScreenPresenter = component.getPresenter();
I don't really have any preference here. The key point is to understand that you should not build the objects yourself (unless inside #Modules). As a rule of thumb any time you see new being used that means you have a tight dependency on that object and you should extract it to be injected. So this is why you should avoid creating the presenter inside your activity. It will couple the presenter to the activity.
Im learning Dagger 2, i have noticed that in some examples there is a #Singleton in the module's methods and on other #Singleton on the Component's methods? What is the difference and what exactly a #Singleton annotation on a module's method and on an component's method mean?
Since you're a beginner, I highly recommend just trying stuff. Writing unit tests is easy enough, and it helps to understand and prove theories.
If you didn't already, read the User's Guide for some basic knowledge about dagger and scopes.
Annotating methods in components (provision methods) doesn't have any effect. You will have to annotate the class or providing method in a module. I want to quickly show how you can just quickly prove this yourself:
We have 2 Component, one using a scope #Singleton, the other one none:
#Singleton
#Component(modules = SingletonModule.class)
public interface SingletonComponent {
Object getObject();
}
#Component(modules = NormalModule.class)
public interface NormalComponent {
#Singleton
Object getObject();
}
With those components come 2 modules, one providing the singleton scoped object (same as the component) the other one just uses no scope:
#Module
public class SingletonModule {
#Provides
#Singleton
public Object provideObject() {
return new Object();
}
}
#Module
public class NormalModule {
#Provides
public Object provideObject() {
return new Object();
}
}
And now we just create a small test:
public class ComponentTest {
#Test
public void testSingletonComponent() {
SingletonComponent component = DaggerSingletonComponent.create();
Assert.assertEquals(component.getObject(), component.getObject());
}
#Test
public void testNormalComponent() {
NormalComponent component = DaggerNormalComponent.create();
Assert.assertNotSame(component.getObject(), component.getObject());
}
}
This test will succeed and prove that annotating methods in components doesn't do anything. Scoping objects in modules, or annotating the class itself when using constructor injection will result in the object being reused within the same scope / the same component.
Creating 2 components of the same scope will also lead to duplicate objects, as can be proven like this:
#Test
public void testTwoSingleonComponents() {
SingletonComponent component1 = DaggerSingletonComponent.create();
SingletonComponent component2 = DaggerSingletonComponent.create();
Assert.assertNotSame(component1.getObject(), component2.getObject());
}
Be sure to read some tutorials and be sure to try things out. The compiler will complain if you do things wrong! :)
I've created a component and it only last for the lifetime of the activity. I did not use any scope annotations and only quick example of the life time of the component looks like this:
public class MainActivity extends AppCompatActivity {
private final String TAG = getClass().getSimpleName();
#Inject
AlmondButter someAlmondButter;
#Inject
CashewSandwich sandwich;
SandwichComponent sandwichComponent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*create thte dependent butter for the sandwich here*/
ButterComponent butterComponent=DaggerButterComponent.builder().
butterModule(new ButterModule()).build();
/*create a scope sandwichcomponent here */
sandwichComponent=DaggerSandwichComponent.builder().sandwichModule(new SandwichModule()).
butterComponent(butterComponent)
.build();
//finally we have a sandwichComponent, lets inject our dependencies
sandwichComponent.inject(this);
Log.v(TAG,sandwich.toString());
Log.v(TAG,someAlmondButter.toString());
}
#Override
protected void onDestroy() {
super.onDestroy();
//not necessary but it clearly shows the scope being tied to lifecycle of activity
sandwichComponent=null;
}
}
none of my components are scoped with anotations and it works fine. So im confused why some recommend to create scope tags, what is there purpose ? i'll show you my components below for reference:
#Component(dependencies = ButterComponent.class, modules = SandwichModule.class)
public interface SandwichComponent {
CashewSandwich ProvideCashewSandwitch();
void inject (MainActivity mainactivity);
}
and the next component:
#Component(modules={ButterModule.class})
public interface ButterComponent {
//these are for our whatever class depends on butter
AlmondButter ProvideAlmondButter();
CashewButter ProvideCashewButter();
}
UPDATE: FOR ANYONE WHO NEEDS HELP WITH UNDERSTANDING THESE CONCEPTS I MADE A BLOG HERE.
By using scopes on component and scopes on module provider method, you can ask Dagger2 to create scoped providers for you.
In order to get a scoped provider in your module's provider method, you must put the scope on the component as well.
You can specify only one scope on a given component, and in a scoped component, you can only have modules with that scope on its provider methods, or the provider methods can also be unscoped.
Unscoped providers give you a new instance on every inject call.
Scoped providers store a single instance for every inject call to that specific component instance.
#Component(modules={HelloModule.class})
#Singleton
public interface HelloComponent {
Hello hello();
World world();
void inject(MainActivity mainActivity);
}
#Module
public class HelloModule {
#Provides
public Hello hello() { return new Hello(); } //new instance each call to inject
#Provides
#Singleton
public World world() { return new World(); } //one instance per component
}
It is also worth noting that if you subscope another component to inherit its dependencies (using subcomponent or component dependency), you can only depend on one other scoped component. Think of it like how "multiple inheritance" is not allowed in Java, you also cannot depend on multiple scoped components and inherit their dependencies, only one.
Typically you have a singleton scope, and you subscope your components according to the top-level separation of modules in your application.
#Component(modules={ApplicationModule.class})
#Singleton
public interface ApplicationComponent {
Something something();
}
#Component(dependencies={ApplicationComponent.class}, modules={MainActivityModule.class})
#ActivityScope
//this is a subscoped component that inherits from ApplicationComponent
public interface MainActivityComponent extends ApplicationComponent {
OtherThing otherThing();
void inject(MainActivity mainActivity);
}
According to Martin Fowler, the right way to slice your application into pieces on the top-level is by features, such as GalleryComponent, SettingsComponent, etc. and not by layers (data, domain, presentation).
Scopes manage the instance creation across multiple requests for the same type. Imagine if you had this:
#Inject
AlmondButter someAlmondButter;
#Inject
AlmondButter otherAlmondButter;
This would create two separate AlmondButter instances. A trivial case, but hopefully it illustrates the point that each time you request the dependency, a new one is created.
Imagine now you have two different classes, each with a field #Inject AlmondButter sharedAlmondButter. If you want them to have the same exact instance, a scope will handle that for you.
Similarly, with any dependency you have, you can inject a Provider<T>, i.e. #Inject Provider<AlmondButter> almondButterProvider. This can allow you to call almondButterProvider.get() to retrieve a new instance. If you then wanted all values returned by .get() to be the same instance, a scope would accomplish the same thing.
Yes, I know this has been asked before, and yes, I know it is "by design".
But I'd like to do something like this:
#Component(modules = {RealmModule.class})
public interface RealmComponent {
Realm realm();
}
#Component(modules = {RepositoryModule.class})
public interface RepositoryComponent {
PersonRepository personRepository();
ScheduleRepository schedulesRepository();
}
#Component(dependencies = {RealmComponent.class, RepositoryComponent.class})
public interface AppDataComponent
extends RealmComponent, RepositoryComponent {
}
#ApplicationScope
#Component(dependencies = {AppContextComponent.class,
AppDataComponent.class,
AppDomainComponent.class,
AppPresentationComponent.class,
AppUtilsComponent.class})
public interface ApplicationComponent
extends AppContextComponent, AppDataComponent, AppDomainComponent, AppUtilsComponent, AppPresentationComponent {
void inject(CustomApplication customApplication);
void inject(DashboardActivity dashboardActivity);
}
However, what I get is unscoped, every time I inject a JobManager or a ScheduleRepository or anything else, I get a new instance. The only way I could "fix" that was this.
#Module
public class JobManagerModule {
private JobManager jobManager;
#Provides
public JobManager jobManager(Context context) {
if(jobManager == null) {
jobManager = new JobManager(context, new Configuration.Builder(context).networkUtil(
new WifiOrMobileNetworkUtil(context)).build());
}
return jobManager;
}
}
Not a fan.
So, how is one meant to structure and rip apart the dependency tree, without making one big gigantic über blob component that has every single module listed and every single provision method (instead of these "subcomponent" component dependencies)?
I tried using subcomponents for this, but then you have to provide every single module for the final ApplicationComponent.
I'm not sure what to do here. I tried specifying #Singleton for every first-level component and #SubcomponentScope for every AppDataLevelComponent, I also tried making a new scope for every single subcomponent, but both of them failed with "cannot depend on multiple scoped components".
EDIT: Apparently in order to get scoped providers, marking the components with the scope is not enough - you must specify the scope for the #Provides annotated methods too.
#Module
public class RepositoryModule {
#Provides
#Singleton
public PersonRepository personRepository() {
return new PersonRepositoryImpl();
}
#Provides
#Singleton
public ScheduleRepository schedulesRepository() {
return new SchedulesRepositoryImpl();
}
}
In the meantime, I ended up with this übercomponent.
#Singleton
#Component(modules = {
AppContextModule.class,
DbMapperModule.class,
DbTaskModule.class,
RealmModule.class,
RepositoryModule.class,
InteractorModule.class,
ServiceModule.class,
PresenterModule.class,
XmlPersisterModule.class
})
public interface ApplicationComponent
extends AppContextComponent, AppDataComponent, AppDomainComponent, AppUtilsComponent, AppPresentationComponent {
Where the xyzComponent classes are just interfaces to store the provision methods...
(Please note that this structure is an anti-pattern as described by Martin Fowler, and you should organize modules based on features / activities, and make them into subscoped components using component dependencies. Component dependencies are used to subscope your superscope components, and "inherit" dependency providers.)
I had same problems like you not while ago and ended using the same ubercomponent approach except I use #Subcomponents in order organize the things and not to have all modules listed in the ubercomponent (I call it "top" or "app's" component).
You may see an example here:
How to migrate missing inject from module with complete = false from Dagger 1 to Dagger 2
In the documentation it says that #Provides methods may have dependencies on their own, like:
#Provides Pump providePump(Thermosiphon pump) {
return pump;
}
What would change if I would write it like that:
#Provides Pump providePump() {
return new Thermosiphon();
}
And in the first snipped: Where does the method get its pump from?
The documentation also shows the Thermosiphon class:
class Thermosiphon implements Pump {
private final Heater heater;
#Inject
Thermosiphon(Heater heater) {
this.heater = heater;
}
...
}
The constructor of this class is annotated with #Inject. This lets Dagger know to use this Constructor whenever a Thermosiphon is necessary, and automatically supplies a Heater instance to it, so you don't have to.
It is perfectly fine for you to create a new Thermospihon instance yourself, but Dagger saves you the trouble by doing it like this. For example, you would need to get some Heater reference from somewhere if you do it manually. That is what Dagger is all about, so you don't have to do the tedious repetitive work.
These are effectively the same IF a new instance of Thermosiphon.class is created every time you request an instance. If it's a singleton (or scoped in any way), then we have a difference.
If you have the following, then the first example is an alias to the singleton. The second example, however, will still create new instances every time.
#Provides
#Singleton
Thermosiphon provideThermosiphon() {
return new Thermosiphon();
}
Personally, I like the first approach better. Using the first approach, you could add or alter the provider later and adjust the scope or the state of the instance before it'a passed to the alias. It seems a little more flexible.
It looks for other beans declared in your module
For example:
#Module
public class MainModule {
#Provides
public EmailServiceApiGateway provideEmailServiceApiGateway() {
return new EmailServiceApiGateway();
}
#Provides
public EmailSendingActivityPresenter provideEmailSendingActivityPresenter(EmailServiceApiGateway emailServiceApiGateway) {
return new EmailSendingActivityPresenterImpl(emailServiceApiGateway);
}
}
So in the case above, EmailServiceApiGateway gets automatically injected into EmailSendingActivityPresenter.