I have the following Dagger2 Architecture in my app:
-- AppComponent (#PerApplication)
-- UserComponent (#PerUser)
-- ActivityComponent (#PerActivity)
-- ChatComponent (#PerActivity) <-- 1
Where:
AppComponent:
#PerApplication
#Component(modules = {ApplicationModule.class, StorageModule.class, NetworkModule.class})
public interface ApplicationComponent {
UserComponent plus(UserModule userComponent);
//Exposed to sub-graphs.
Context application();
}
UserComponent:
#PerUser
#Subcomponent(modules = {UserModule.class, RosterModule.class})
public interface UserComponent {
ActivityComponent plus(ActivityModule activityModule);
User getMe();
UserRepository userRepository();
}
ActivityComponent:
#PerActivity
#Subcomponent(modules = ActivityModule.class)
public interface ActivityComponent {
ChatComponent plus(ChatModule chatComponent);
//Exposed to sub-graphs.
Context context();
}
ChatComponent:
#PerActivity
#Subcomponent(modules = {ChatModule.class})
public interface ChatComponent {
void inject(ChatListFragment chatListFragment);
void inject(ConversationFragment conversationFragment);
void inject(NewConversationFragment newConversationFragment);
void inject(CloudFilesFragment cloudFilesFragment);
void inject(ChatActivity chatActivity);
void inject(ConversationActivity conversationActivity);
void inject(NewConversationActivity newConversationActivity);
void inject(NewGroupActivity newGroupActivity);
void inject(NewGroupFragment newGroupFragment);
}
I'm facing 2 problems:
First, how can I inject different Context to my classes ? Either App or Activity ??
And secondly, I'm facing a bizarre issue when trying to compile my code, the error is:
Error:(23, 10) error:
br.com.animaeducacao.ulife.domain.interactor.UseCase cannot be
provided without an #Provides-annotated method.
br.com.animaeducacao.ulife.presentation.view.fragment.ChatListFragment.chatListPresenter
[injected field of type:
br.com.animaeducacao.ulife.presentation.presenter.ChatListPresenter
chatListPresenter]
br.com.animaeducacao.ulife.presentation.presenter.ChatListPresenter.(br.com.animaeducacao.ulife.domain.interactor.UseCase
chatDialogsUseCase,
br.com.animaeducacao.ulife.domain.interactor.UseCase
adviceUserPresence, android.content.Context context) [parameter:
#javax.inject.Named("getChatDialogs")
br.com.animaeducacao.ulife.domain.interactor.UseCase
chatDialogsUseCase]
My ChatListFragment is:
#PerActivity
public class ChatListFragment extends BaseFragment implements ChatListView {
#Inject
ChatListPresenter chatListPresenter;
...
//called onActivityCreated()
private void initialize() {
this.getComponent(ChatComponent.class).inject(this);
}
BaseFragment:
protected <C> C getComponent(Class<C> componentType) {
return componentType.cast(((HasComponent<C>)getActivity()).getComponent());
}
ChatListPresenter:
#PerActivity
public class ChatListPresenter implements Presenter {
private final UseCase chatDialogsUseCase;
private final UseCase adviceUserPresence;
private final Context context;
private ChatListView chatListView;
#Inject
public ChatListPresenter(#Named("getChatDialogs") UseCase chatDialogsUseCase,
#Named("adviceUserPresence") UseCase adviceUserPresence,
Context context) {
this.chatDialogsUseCase = chatDialogsUseCase;
this.adviceUserPresence = adviceUserPresence;
this.context = context;
}
The problem is, in my ChatModule class I have implemented all the #Provides necessary:
#Provides
#PerActivity
#Named("getChatDialogs")
public UseCase provideChatDialogs(#Named("transactionalChatRepository") ChatRepository chatRepository, ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
return new GetUserChatDialogs(chatRepository, threadExecutor, postExecutionThread);
}
Is this a good approach ? Why is this not compiling, what I am missing here ?
Sorry for the long post and thanks !
Ah, you have multiple problems.
1.) While you're using the subscoping correctly to a point (you are making #Subcomponents properly at first), the ChatComponent doesn't actually subscope its parent component - basically, ChatComponent cannot be #PerActivity, it needs to be a fourth scope.
#Subcomponent annotation is just a way to create a subscoped component without having to specify it as a component dependency. It still needs its own "more specific" scope.
2.) to make subscoping work, you need to specify provision methods in your component for every dependency that that component is meant to provide, so that the subscoped components can inherit them.
For example, your ApplicationComponent doesn't have provision methods for what is in StorageModule, and therefore the dependencies provided by StorageModule cannot be inherited to subscoped components.
I however am not sure if you can just specify the class you're providing if it is not inside a module, and instead it is annotated with #Inject constructor and the class is marked with the scope.
Also, to allow in a scope hierarchy A->B->C for C to inherit from A, then B needs to have the provision methods of A as well.
So UserComponent extends ApplicationComponent is necessary, and ActivityComponent extends UserComponent, and ChatComponent extends ActivityComponent.
3.) You should use the #Named("application") and #Named("activity") annotations to specify two different Context, or instead just refer to them as Application and Activity in your module so that they don't get mixed up.
Related
I am creating a basic Android application with Dagger 2. I was having a lot of difficulty understanding how to use it properly until I came across this great talk by Jake Wharton. In it, he demonstrates using Dagger 2 with a "Tweeter" app. At ~22:44, he shows that an app's #Inject fields can be satisfied with an inject method. He later shows a simple Android implementation of this.
My app's ViewModels rely on a repository class. I'm using Dagger 2 to inject this repository into the ViewModels, through the Application class, like this:
//In my Dagger 2 component
#Singleton
#Component(module = {MyRepositoryModule.class})
public interface MyRepositoryComponent{
void inject(MyViewModel viewModel);
}
//In MyApplication
public class MyApplication extends Application{
private MyRepositoryComponent repoComponent;
//Instantiate the component in onCreate...
public MyRepositoryComponent getMyRepositoryComponent(){
return repoComponent;
}
}
//Finally, in my ViewModel
public MyViewModel extends AndroidViewModel{
#Inject
public MyRepository repo;
public MyViewModel(#NonNull MyApplication app){
repo = app.getMyRepositoryComponent().inject(this);
}
}
I went with this approach because I can override the MyApplication class and use fake components for testing (which is one of my main goals here). Previously, the only way I was able to inject dependencies was by building my component inside the ViewModels, which makes it impossible to substitute with fakes.
For a simple app like this, I know I could just do away with the inject method and hold a reference to the repository in the MyApplication class. However, assuming there are more dependencies to worry about, would this be a common/good/testing-friendly approach to injecting dependencies for Activities and ViewModels in Android?
After inspiration from EpicPandaForce's answer and some research (see this article), I've found a solution I'm happy with.
I decided to drop Dagger 2 from my project because I was over-engineering it. My app relies on a repository class and now a ViewModelProvider.Factory implementation, which are both needed as soon as the app runs. I learned enough about Dagger for my own satisfaction, so I feel comfortable leaving it out of this particular project and creating the two dependencies in an Application class. These classes look like this:
My Application class, which creates my ViewModel Factory, gives it it's repository, and exposes a getViewModelFactory() method to my Activities:
public class JourneyStoreApplication extends Application {
private final JourneyStoreViewModelFactory journeyStoreViewModelFactory;
{
// Instantiate my viewmodel factory with my repo here
final JourneyRepository journeyRepository = new JourneyRepositoryImpl();
journeyStoreViewModelFactory = new JourneyStoreViewModelFactory(journeyRepository);
}
#Override
public void onCreate() {
super.onCreate();
}
public JourneyStoreViewModelFactory getViewModelFactory(){
return journeyStoreViewModelFactory;
}
}
My ViewModel Factory, which creates new ViewModels with a repository reference. I'll be expanding this as I add more Activity classes and ViewModels:
public class JourneyStoreViewModelFactory implements ViewModelProvider.Factory {
private final JourneyRepository journeyRepository;
JourneyStoreViewModelFactory(JourneyRepository journeyRepository){
this.journeyRepository = journeyRepository;
}
#NonNull
#Override
public <T extends ViewModel> T create(#NonNull Class<T> modelClass) {
if(modelClass == AddJourneyViewModel.class){
// Instantiates the ViewModels with their repository reference.
return (T) new AddJourneyViewModelImpl(journeyRepository);
}
throw new IllegalArgumentException(String.format("Requested class %s did not match expected class %s.", modelClass, AddJourneyViewModel.class));
}
}
My AddJourneyActivity class, which uses the AddJourneyViewModel:
public class AddJourneyActivity extends AppCompatActivity {
private static final String TAG = AddJourneyActivity.class.getSimpleName();
private AddJourneyViewModel addJourneyViewModel;
private EditText departureTextField;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_journey);
JourneyStoreApplication app = (JourneyStoreApplication) getApplication();
addJourneyViewModel = ViewModelProviders
// Gets the ViewModelFactory instance and creates the ViewModel.
.of(this, app.getViewModelFactory())
.get(AddJourneyViewModel.class);
departureTextField = findViewById(R.id.addjourney_departure_addr_txt);
}
//...
}
But this still leaves the question of testing, which was one of my main issues.
Side note: I made all of my ViewModel classes abstract (with just methods) and then I implemented them for my real app and the test code. This is because I find it easier than extending my ViewModels directly, then trying to override their methods and shadow their state to create a fake version.
Anyway, I extended my JourneyStoreApplication class (contradicting myself I know, but it's a small class so it's easy to manage) and used that to create a place to provide my fake ViewModels:
public class FakeJourneyStoreApplication extends JourneyStoreApplication {
private final JourneyStoreViewModelFactory fakeJourneyStoreViewModelFactory;
{ // Create my fake instances here for my tests
final JourneyRepository fakeJourneyRepository = new FakeJourneyRepositoryImpl();
fakeJourneyStoreViewModelFactory = new FakeJourneyStoreViewModelFactory(fakeJourneyRepository);
}
#Override
public void onCreate() {
super.onCreate();
}
public JourneyStoreViewModelFactory getViewModelFactory(){
return fakeJourneyStoreViewModelFactory;
}
}
I made fake implementations of my ViewModels and returned instances of them from FakeJourneyStoreViewModelFactory. I might simplify this later as there's probably more "fake" boilerplate than there needs to be.
Going off this guide (section 4.9), I extended AndroidJUnitRunner to provide my fake Application to my tests:
public class CustomTestRunner extends AndroidJUnitRunner {
#Override
public Application newApplication(ClassLoader cl, String className, Context context)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
return super.newApplication(cl, FakeJourneyStoreApplication.class.getName(), context);
}
}
And finally, I added the custom test runner to my build.gradle file:
android {
defaultConfig {
// Espresso
testInstrumentationRunner "com.<my_package>.journeystore.CustomTestRunner"
}
}
I'm going to leave this question open for another 24 hours in case anyone has useful things to add, then I'll choose this as the answer.
I have an app with activities and fragments with dependencies injected via dagger 2
I am able to do field injection in activities and fragments but not able to do constructor injection in other classes.
Here's my relevant code
#Module
public abstract class MainFragmentProvider {
#ContributesAndroidInjector(modules = HomeFragmentModule.class)
abstract HomeFragment provideHomeFragmentFactory();
}
and
#Module
public class HomeFragmentModule {
...
#Provides
static HomePresenter provideHomePresenter(HomeView homeView, HomeInteractor homeInteractor) {
return new HomePresenter(homeView, homeInteractor);
}
How can I write code so that I can get dependencies directly in HomePresenter by constructor injection instead of writing provideMethods in module. I am doing this because every time I want to change the constructor arguments in this case, I need to change the module code as well.
How can I do something like this in HomePresenter's constructor?
#Inject
public HomePresenter(HomeView homeView, HomeInteractor homeInteractor) {
this.homeInteractor = homeInteractor;
this.homeView = homeView;
}
To inject constructor, Dagger has to know where to get parameters passed to it i.e.
you have to provide
HomeView homeView, HomeInteractor homeInteractor
So create also methods for providing other dependencies:
#Provides
static HomeView provideHomeView() {
return ...
}
#Provides
static HomeInteractor provideHomeInteractor() {
return ...
}
I don't know much about the android extensions for dagger 2 but as far as I know there are two ways to achieve the result you are looking for.
In the relevant component you can specify a method with your type:
interface SomeComponent {
HomePresenter presenter(); // Method name does not matter here, only the type
}
and access it like this
class Home {
HomePresenter presenter;
void initialize() { //This could be your onCreate or wherever you typically inject
presenter = getSomeComponent().presenter();
}
}
or you can request it if you specify an inject method for your Home object:
interface SomeComponent {
void inject(Home home);
}
class Home {
#Inject HomePresenter presenter;
void initialize(){
getSomeComponent().inject(this);
}
}
In both cases you must ensure your Component includes the appropriate Modules.
I'm fairly new to Dagger 2 and I have the following classes.
I have 2 modules:
DaoSessionModule
#Module
public class DaoSessionModule {
private DaoSession daoSession;
private Context context;
public DaoSessionModule(Context context) {
this.context = context;
if(daoSession == null) {
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this.context, "my_pocket");
Database db = helper.getWritableDb();
daoSession = new DaoMaster(db).newSession();
}
}
#Provides
LanguageDao providesLanguageDao() {
return daoSession.getLanguageDao();
}
#Provides
CategoryDao providesCategoryDao() {
return daoSession.getCategoryDao();
}
}
and GlobalPrefModule
#Module
public class GlobalPrefModule {
private GlobalPref globalPerf;
public GlobalPrefModule(GlobalPref globalPerf) {
this.globalPerf = globalPerf;
}
#Provides
public GlobalPref providesGlobalPref() {
return this.globalPerf;
}
}
and their components go as:
#Singleton
#Component(modules = {DaoSessionModule.class})
public interface DaoSessionComponent {
void inject(SplashActivity activity);
}
and
#Singleton
#Component(modules = {GlobalPrefModule.class })
public interface GlobalPrefComponent {
void inject(SplashActivity activity);
}
and I build both in my application class:
daoSessionComponent = DaggerDaoSessionComponent.builder()
.daoSessionModule(new DaoSessionModule(this))
.build();
globalPrefComponent = DaggerGlobalPrefComponent.builder()
.globalPrefModule(new GlobalPrefModule(new GlobalPref()))
.build();
and inject them in my splash activity:
public class SplashActivity extends BaseActivity {
#Inject
LanguageDao languageDao;
#Inject
GlobalPref globalPerf;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initInjections();
}
private void initInjections() {
ZoopiApplication.app().getDaoSessionComponent().injectDao(this);
ZoopiApplication.app().getGlobalPrefComponent().injectGlobalPref(this);
}
}
now the problem I'm facing is that if I only inject DaoSession in my splash and comment out the GlobalPref impl it'll simply work but the moment I add GlobalPref along side with Daosession it fails to build and gives me the following error messages:
Error:(8, 52) error: cannot find symbol class DaggerDaoSessionComponent
Error:(9, 52) error: cannot find symbol class DaggerGlobalPrefComponent
Error:(16, 10) error: mypocket.com.zoopi.GlobalPref cannot be provided without an #Inject constructor or from an #Provides- or #Produces-annotated method.
mypocket.com.zoopi.GlobalPref is injected at
mypocket.com.zoopi.activities.SplashActivity.globalPerf
mypocket.com.zoopi.activities.SplashActivity is injected at
mypocket.com.zoopi.dagger.dagger2.components.DaoSessionComponent.injectDao(activity)
Error:(16, 10) error: mypocket.com.zoopi.models.LanguageDao cannot be provided without an #Inject constructor or from an #Provides- or #Produces-annotated method.
mypocket.com.zoopi.models.LanguageDao is injected at
mypocket.com.zoopi.activities.SplashActivity.languageDao
mypocket.com.zoopi.activities.SplashActivity is injected at
mypocket.com.zoopi.dagger.dagger2.components.GlobalPrefComponent.injectGlobalPref(activity)
and both generated classes DaggerDaoSessionComponent and DaggerGlobalPrefComponent are generated in the build foloder.
What could be the reason that I can't inject both objects into the same activity?
Injection has to be done from one component, and one component only.
It should be easy to see that the error message states that the object that can't be provided is the one you try to inject by the other component.
Dagger does not do "half" injections and one component has to inject all the fields. If partial injection would be possible you could end up with inconsistent states, since Dagger has no way of knowing how, when, or where you'd inject the rest of the fields. In short, it's just not possible. You'll have to use a single component.
but then I'll have many more modules soon and I don't know if it's a good idea to have one component to handle all modules...
That's okay. You will end up with quite a bunch of modules and possible quite a few components, depending on your setup. Make sure to use SubComponents where appropriate and you can even have modules include other modules, if you have big dependency groups split over multiple modules.
I'm quite new to Dagger 2 and I'm looking for a way to have a "configurable component".
Essentially this is what I want to achieve:
public interface ErrorReporter{
...
}
public class ConsoleErrorReporter implements ErrorReporter{
... // Print to System.err
}
public class DialogErrorReporter implements ErrorReporter{
... // Show modal dialog to user
}
#Module
public interface UIModule{
#Provides
ErrorReporter provideErrorReporter();
}
#Module
public class ConsoleUIModule{
#Override
#Provides
ErrorReporter provideErrorReporter(ConsoleErrorReporter cer){
return cer;
}
}
#Module
public class GraphicalUIModule{
#Override
#Provides
ErrorReporter provideErrorReporter(DialogErrorReporter der){
return der;
}
}
#Component(modules = {UIModule.class, OtherUniversalModule.class})
public interface ApplicationComponent{
ErrorReporter errorReporter();
}
void main(String[] args){
final UIModule uiModule;
if(args.length == 1 && args[0].equals("gui")){
uiModule = new GraphicalUIModule();
}else{
uiModule = new ConsoleUIModule();
}
DaggerApplicationComponentdac = DaggerApplicationComponent.builder()
.uiModule(uiModule).build();
dac.errorReporter().showError("Hello world!");
}
The above fails with #Provides methods cannot be abstract unfortunately both for interfaces and abstract classes. I have also tried non-abstract base class with concrete implementations that return null and then overriding these in sub classes. However this also fails with #Provides methods may not override another method.
In short I want to define a contract for a module and choose different modules during runtime. I know that Dagger 2 compile time validates the object graph, but if I have a well defined contract that should still be possible right? Or am I forced to create two different components with duplicate code for both user interfaces? Are there other solutions that I'm missing?
I don't think using a module this way is possible, because...
Suppose you have the following two constructors for your classes
#Inject ConsoleErrorReporter(Console console);
#Inject DialogErrorReporter(Graphics graphics);
This would mean that ConsoleUIModule would require a Console and DialogErrorReporter would require a Graphics object to create their respecitve implementation of ErrorReporter.
But if dagger only knows about UIModule because you use the interface there...well...it could not provide the dependencies for either, because it doesn't know about any of them.
And if you don't know the dependencies building a dependency graph at compile time won't work. Also this won't compile even without dagger because provideErrorReporter(ConsoleErrorReporter cer) does not override provideErrorReporter().
What you can and should do is use different components. Because a component is the thing that actually knows how to provide things. And a component already is an interface—and that's what you wanted, right?
You can have component dependencies, where one component depends on another. E.g. have a DependentComponent that provides a NeedsErrorReporter that needs an implementation of ErrorReporter. We also depend on an interface, rather than the actual component (and that's what you wanted after all, right?)
You then implement the interface by actual components, and each component has its respective modules (and maybe even further dependencies). In the end you have a component that you can switch and will provide different versions of an object, properly encapsulated!
#Component(dependencies = UIComponent.class) /* <- an interface! */
interface DependentComponent {
NeedsErrorReporter needsErrorReporter();
}
class NeedsErrorReporter {
#Inject public NeedsErrorReporter(ErrorReporter reporter) { }
}
/* this is _not_ a component, but a simple interface! */
interface UIComponent {
ErrorReporter errorReporter();
}
/* Console */
#Component(modules = ConsoleUIModule.class)
interface ConsoleUIComponent extends UIComponent { }
#Module interface ConsoleUIModule {
#Binds ErrorReporter provideErrorReporter(ConsoleErrorReporter cer);
}
/* Graphic */
#Component(modules = GraphicalUIModule.class)
interface GraphicUIComponent extends UIComponent { }
#Module interface GraphicalUIModule {
#Binds ErrorReporter provideErrorReporter(DialogErrorReporter der);
}
/* The error reporter variants */
interface ErrorReporter {
}
class ConsoleErrorReporter implements ErrorReporter {
#Inject public ConsoleErrorReporter() { }
}
class DialogErrorReporter implements ErrorReporter {
#Inject public DialogErrorReporter() { }
}
Now all you have to do is pick the right component ;)
DaggerDependentComponent.builder().uIComponent(DaggerConsoleUIComponent.create()).build();
// or
DaggerDependentComponent.builder().uIComponent(DaggerGraphicUIComponent.create()).build();
I am currently trying to integrate Dagger 2 into an Android application. My project setup is as follows:
library
app (depends on library)
In my library project I defined a class that I'll later inject into other classes that need it (Activities and regular classes) in the library as well as the app project.
#Singleton
public class MyManager{
#Inject
public MyManager(){
//Do some initializing
}
}
Now - for instance in my Fragments or Activities or regular classes I'd inject the above Singleton as follows:
public class SomeClass{
#Inject
MyManager myManager;
}
Or so I thought, because in practice myManager is always null. And apparently it's constructor is never called either, so I guess I must be missing something configuration-wise? Or maybe I misunderstood the documentation and it's not meant to work this way at all? The purpose of MyManager class is to be an application-wide accessible component-accumulating entity - that's why I went for the #Singleton.
UPDATE
To avoid confusion: I mentioned my having components somewhere in a comment I think - this refers to components in the sense of "component based design" and has nothing to do with dagger. The dagger-based code I have is all listed above - there is nothing else related to dagger in my code.
When I started adding #Component I had some compiler issues, because my dagger2 was not setup properly - check out this really helpful thread on how to setup dagger2 correctly: https://stackoverflow.com/a/29943394/1041533
UPDATE 2
Here is my updated code, based on G. Lombard's suggestions - I changed the code as follows - the original Singleton is in the library project:
#Singleton
public class MyManager{
#Inject
public MyManager(){
//Do some initializing
}
}
Also in the library project is the bootstrap class:
#Singleton
#Component
public interface Bootstrap {
void initialize(Activity activity);
}
Then I use the above Bootstrap class in my activity (in my concrete app, NOT in the library project! I do however also have Classes/Activities in the library that'll access Bootstrap to inject MyManager):
public class MyActivity extends Activity{
#Inject
MyManager manager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//DONT DO THIS !!! AS EXPLAINED BY EpicPandaForce
DaggerBootstrap.create().initialize(this);
}
}
But even after this line:
DaggerBootstrap.create().initialize(this);
the manager instance is still null, i.e. not injected.
I just found this: https://stackoverflow.com/a/29326023/1041533
Which if I don't misread, implies I need to specify every single class in the Bootstrap class that will use #Inject to have stuff injected. Sadly - this is not an option, as I have more than 40 classes and activities for which I'd have to do that.
Meaning my Bootstrap interface apparently would have to look something like this:
#Singleton
#Component
public interface Bootstrap {
void initialize(ActivityA activity);
void initialize(ActivityB activity);
void initialize(ActivityC activity);
void initialize(ActivityD activity);
void initialize(ActivityE activity);
void initialize(ActivityF activity);
//and so on and so forth...
}
If the above is true, that would not be worth it for my use case. Plus: Seems there is no compile-time check, if I forgot to specify one of my 40+ classes here? It just wont work - i.e. crash the app at runtime.
You're making a mistake in that you are using
DaggerBootstrap.create().initialize(this);
in your Activity, as scopes are not shared across multiple component instances. What I recommend is using a custom application class
public class CustomApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Bootstrap.INSTANCE.setup();
}
}
#Component
#Singleton
public interface _Bootstrap {
void initialize(ActivityA activityA);
//void initiali...
}
public enum Bootstrap {
INSTANCE;
private _Bootstrap bootstrap;
void setup() {
bootstrap = Dagger_Bootstrap.create();
}
public _Bootstrap getBootstrap() {
return bootstrap;
}
}
Then you could call it as
Bootstrap.INSTANCE.getBootstrap().initialize(this);
This way, you share the component across your classes. I personally named Bootstrap as injector, and _Bootstrap as ApplicationComponent, so it looks like this:
Injector.INSTANCE.getApplicationComponent().inject(this);
But that's just my typical setup. Names don't really matter.
EDIT: To your last question, you can solve this by subscoping and component dependencies.
Your library project should be able to see only the library classes, correct? In that case, all you do is
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface LibraryScope {
}
#Component(modules={LibraryModule.class})
#LibraryScope
public interface LibraryComponent {
LibraryClass libraryClass(); //provision method for `MyManager`
}
#Module
public class LibraryModule {
#LibraryScope
#Provides
public LibraryClass libraryClass() { //in your example, LibraryClass is `MyManager`
return new LibraryClass(); //this is instantiation of `MyManager`
}
}
public enum LibraryBootstrap {
INSTANCE;
private LibraryComponent libraryComponent;
static {
INSTANCE.libraryComponent = DaggerLibraryComponent.create();
}
public LibraryComponent getLibraryComponent() {
return libraryComponent;
}
}
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface ApplicationScope {
}
#Component(dependencies={LibraryComponent.class}, modules={AdditionalAppModule.class})
#ApplicationScope
public interface ApplicationComponent extends LibraryComponent {
AdditionalAppClass additionalAppClass();
void inject(InjectableAppClass1 injectableAppClass1);
void inject(InjectableAppClass2 injectableAppClass2);
void inject(InjectableAppClass3 injectableAppClass3);
}
#Module
public class AdditionalAppModule {
#ApplicationScope
#Provides
public AdditionalAppClass additionalAppClass() { //something your app shares as a dependency, and not the library
return new AdditionalAppClass();
}
}
public enum ApplicationBootstrap {
INSTANCE;
private ApplicationComponent applicationComponent;
void setup() {
this.applicationComponent = DaggerApplicationComponent.builder()
.libraryComponent(LibraryBootstrap.INSTANCE.getLibraryComponent())
.build();
}
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
}
Then
#Inject
LibraryClass libraryClass; //MyManager myManager;
...
ApplicationBootstrap.INSTANCE.getApplicationComponent().inject(this);
It's hard to say what your problem was, since you didn't show what your Component looks like and whether you have multiple components etc.
Assuming this logical structure:
/app
MainComponent
SomeClass // where MyManager is to be injected
MainActivity // where SomeClass is to be injected
/library
LibraryComponent
MyManager // Singleton
Then your classes as listed would inject correctly with the following configuration:
#Singleton
#Component
public interface LibraryComponent {
MyManager getMyManager();
}
and the app-level component to inject dependencies into the activity:
#ActivityScope
#Component(dependencies = LibraryComponent.class)
public interface MainComponent {
void inject(MainActivity mainActivity);
}
Note that MainComponent depends on LibraryComponent, but because the latter has singleton scope, you need to define a scope for the other one too, which I was I used the "activity scope" here. (Or you could also just make the MainComponent a singleton and get rid of the LibraryComponent completely if that suits your needs.)
Finally it's all injected into the activity like this:
#Inject
SomeClass someClass;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder()
.libraryComponent(DaggerLibraryComponent.create())
.build()
.inject(this);
someClass.doSomething();
}
I've put a working sample here on GitHub
Update 1:
If I understand your setup correctly, you've so far only used the #Singleton and #Inject annotations on the two classes listed (MyManager and SomeClass), and there is no other Dagger-related code in your project.
In that case, the reason your MyManager isn't getting injected, is because Dagger doesn't know how to provide/instantiate the dependencies. This is where the "components" come in that I mentioned above. Without any Dagger 2 components (interface or abstract class annotated with #Component), your dependencies won't get injected automatically.
I don't know if you have experience with Dependency Injection concepts, but assuming you don't, I'll step through the minimum basics you'll need to understand to get your MyManager injected into SomeClass:
First: when you use DI, you need to understand the difference between "newables" and "injectables". This blogpost by Misko Hevery explains the details.
This means, you can't new up your SomeClass. This won't work:
mSomeClass = new SomeClass();
Because if you did that (say in an activity or fragment), Dagger will have no idea that you expected a dependency to get injected into SomeClass and it has no opportunity to inject anything.
In order for its dependencies to get injected, you have to instantiate (or inject) SomeClass itself through Dagger too.
In other words, say in your Activity where SomeClass is used, you'll need:
#Inject
SomeClass mSomeClass;
Next, you need a Dagger component to perform the actual injection. To create a component, you create an interface with a method that takes your root object (say MainActivity) as argument, e.g.:
#Singleton
#Component
public interface Bootstrap {
void initialize(MainActivity activity);
}
Now when you build your project, Dagger 2 generates a class called DaggerBootstrap that implements this interface. You use this generated class to perform the injection, say in your activity's onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerBootstrap.create().initialize(this);
mSomeClass.doSomething();
}
I believe this generated component is the key part you're missing. Full code for above here.
Some useful Dagger 2 resources:
the official Dagger 2 guide
reddit page with lots of links
Update 2:
Seems like the final missing piece of the puzzle was that your component provided an inject method for the Activity base class, but not for your actual concrete activity.
Unfortunately Dagger 2 requires an inject method for each activity or other class you want to inject into.
As you mentioned, this will be annoying when you have many different activities in your app. There some possible workarounds for this, search for "dagger 2 inject base class", for example this suggestion by #EpicPandaForce: Dagger 2 base class injections
Also note, as pointed out by #EpicPandaForce in the comments, that in my simplistic example I called DaggerLibraryComponent.create() every time which is probably not what you want, since that component is supposed to provide your singletons, so you're probably better off getting the existing instance from somewhere else such as from your Application instance.