i am trying to inject the activity context inside ImageUtls class:
public class ImageUtls {
private Context mContext;
#Inject
public ImageUtls(#ActivityContext Context context) {
this.mContext = context;
}
}
AppModule:
#Module
public class AppModule {
#Provides
#ActivityContext
Context provideActivityContext(Activity activity) {
return activity;
}
#Provides
#ApplicationContext
Context provideContext(Application application) {
return application;
}
}
ActivityBuilder:
#Module
public abstract class ActivityBuilder {
#ContributesAndroidInjector(modules = {OwnerActivityModule.class})
abstract OwnerActivity bindOwnerActivity();
}
OwnerActivityModule:
#Module
public abstract class OwnerActivityModule {
#Provides
abstract Activity bindActivity(OwnerActivity activity);
}
OwnerActivity injection:
public class OwnerActivity extends BaseActivity {
#Inject
ImageUtls imageUtls;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}
AppComponent:
#Singleton
#Component(modules = {AndroidInjectionModule.class, AppModule.class, ActivityBuilder.class})
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance Builder application(Application application);
AppComponent build();
}
void inject(MyApplication application);
}
I am not getting a relevant error about what is going wrong..Can anybody address the issue?
Related
I studied some tutorials about new dagger.android approach but can't make it right. I built a simple tutorial with subcomponent builder but i can't convert this to new approach. All tutorials and articles leave required parts empty.
This example is for learning purposes may not be suitable for practical situations and i only intended implementing field injection, constructor injection may be more appropriate.
Scope
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface ActivityScope {
}
Parent Component
#Component(modules = ApplicationModule.class)
#Singleton
public interface ApplicationComponent {
// Calls SubComponent Builder from MainActivity using ApplicationComponent
ToastMakerSubComponent.Builder toastMakerBuilder();
}
Parent Module, i didn't use #BindsInstance in app module for learning different approaches
#Module(subcomponents = {ToastMakerSubComponent.class})
public class ApplicationModule {
private Context context;
public ApplicationModule(Context context) {
this.context = context;
}
#Provides
#Singleton
SharedPreferences provideSharedPreferences() {
System.out.println("ApplicationModule context: " + context);
return context.getSharedPreferences("PrefName", Context.MODE_PRIVATE);
}
}
Sub Component
#ActivityScope
#Subcomponent(modules = {ToastMakerModule.class})
public interface ToastMakerSubComponent {
void inject(MainActivity mainActivity);
/*
Builder is called from Parent Component,
and parent component is called from scope(Activity, Fragment, etc.)
*/
#Subcomponent.Builder
interface Builder {
ToastMakerSubComponent build();
#BindsInstance
Builder context(Context context);
}
}
Sub Component Module
#Module
public class ToastMakerModule {
#ActivityScope
#Provides
ToastMaker provideToastMaker(Context context) {
System.out.println("ToastMakerModule context: " + context);
return new ToastMaker(context);
}
}
Instantiate ApplicationComponent inside MyApplication
mApplicationComponent = DaggerApplicationComponent
.builder()
.applicationModule(new ApplicationModule(getApplicationContext()))
.build();
And get sub component inside Activity
ApplicationComponent applicationComponent = ((MyApplication) getApplication()).getApplicationComponent();
ToastMakerSubComponent toastMakerSubComponent = applicationComponent
.toastMakerBuilder()
.context(this)
.build();
toastMakerSubComponent.inject(this);
After following this, this, and this tutorial i built the following as
#Component(modules = ApplicationModule.class)
#Singleton
public interface ApplicationComponent {
// What should i put here ???
}
Parent module but i didn't get how i should provide provideSharedPreferences
#Module(subcomponents = {ToastMakerSubComponent.class})
abstract class ApplicationModule {
#Binds
#IntoMap
#ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends MainActivity>
bindYourActivityInjectorFactory(ToastMakerSubComponent.Builder builder);
}
Sub component is missing ToastMakerSubComponent build(); and #BindsInstance Builder context(Context context); how should i add these to this component.
#ActivityScope
#Subcomponent(modules = {ToastMakerModule.class})
public interface ToastMakerSubComponent extends AndroidInjector<MainActivity> {
// ??? Is this required?
void inject(MainActivity mainActivity);
#Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainActivity> {
???
}
}
Also i see #ContributesAndroidInjector, where does it fit in this example?
Here's the diff of changes: https://www.diffchecker.com/3IL8UQ7P
Make app component extend AndroidInjector<MyApplication> and include the AndroidSupportInjectionModule
#Component(modules = {ApplicationModule.class, AndroidSupportInjectionModule.class})
#Singleton
public interface ApplicationComponent extends AndroidInjector<MyApplication> {
}
Make the subcomponent extend AndroidInjector<MainActivity> and the builder AndroidInjector.Builder<MainActivity>, use seedInstance to provide arguments to #BindsInstance methods.
#ActivityScope
#Subcomponent(modules = {ToastMakerModule.class})
public interface ToastMakerSubComponent extends AndroidInjector<MainActivity> {
#Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainActivity> {
#Override
public void seedInstance(MainActivity instance) {
context(instance);
}
#BindsInstance
public abstract Builder context(Context context);
}
}
Add a binding for the subcomponent builder to a module installed in the app component:
#Module(subcomponents = {ToastMakerSubComponent.class})
public abstract class ApplicationModule {
private Context context;
public ApplicationModule(Context context) {
this.context = context;
}
#Provides
#Singleton
SharedPreferences provideSharedPreferences() {
System.out.println("ApplicationModule context: " + context);
return context.getSharedPreferences("PrefName", Context.MODE_PRIVATE);
}
#Binds
#IntoMap
#ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends Activity> bindMainActivityFactory(ToastMakerSubComponent.Builder builder);
}
Let framework classes extend the Dagger* counterparts, or implement Has*Injector interfaces if you can't use inheritance
public class MyApplication extends DaggerApplication {
#Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerApplicationComponent.create();
}
}
public class MainActivity extends DaggerAppCompatActivity {
#Inject
SharedPreferences sharedPreferences;
#Inject
ToastMaker toastMaker;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toastMaker.showToast("sharedPreferences " + sharedPreferences);
}
}
I'm trying to Inject my ToDoRepository to my ToDoDeleteNotificationService and always I get this repository null. I don't know if I have to do another Module more or if I can't do it in a IntentService.
#Module
public class ToDoRepositoryModule {
#Provides
#Singleton
ToDoDatabase provideDatabase(Application application) {
return Room.databaseBuilder(application,
ToDoDatabase.class, "ToDo.db")
.build();
}
#Provides
#Singleton
ToDoDao provideUserDao(ToDoDatabase database) {
return database.toDoDao();
}
#Provides
#Singleton
AppExecutors provideAppExecutors() {
return new AppExecutors();
}
#Provides
#Singleton
ToDoRepository providesToDoRepository(ToDoDao toDoDao, AppExecutors appExecutors) {
return new ToDoRepository(toDoDao, appExecutors);
}
}
-- When my class TodoDeleteNotiricationService is called, I get my todoId byt my repository is null
public class ToDoDeleteNotificationService extends IntentService {
#Inject
ToDoRepository mToDoRepository;
public ToDoDeleteNotificationService() {
super("ToDoDeleteNotificationService");
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
assert intent != null;
String toDoId = intent.getStringExtra(ToDoNotificationsService.TODO_MODEL_KEY);
mToDoRepository.deleteToDo(toDoId);
}
}
--
#Singleton
#Component(modules = {ToDoRepositoryModule.class,
ActivityBindingModule.class,
AppModule.class,
AndroidSupportInjectionModule.class})
public interface AppComponent extends AndroidInjector<ToDoApplication>{
ToDoRepository getToDoRepository();
#Component.Builder
interface Builder{
#BindsInstance
AppComponent.Builder application(Application application);
AppComponent build();
}
}
I am trying to learn Dagger2 from this medium article and pass RequestQueue as an activity level dependency:
https://proandroiddev.com/dagger-2-annotations-binds-contributesandroidinjector-a09e6a57758f
I can create application components just fine but I am facing a lot of trouble with ContributesAndroidInjector.
Application Class:
public class PokemonApplication extends Application {
private static AppComponent appComponent;
public static AppComponent getAppComponent(){
return appComponent;
}
#Override
public void onCreate() {
super.onCreate();
appComponent=buildMyComponent();
}
private AppComponent buildMyComponent() {
return DaggerAppComponent.builder().appmod(this).build();
}
}
AppModule:
#Module
public abstract class AppModule {
#ContributesAndroidInjector(modules = VolleyModule.class)
abstract MainActivity mainActivity();
#Provides
#Singleton
static SharedPreferences providePreferences(Application application) {
return application.getSharedPreferences("data", Context.MODE_PRIVATE);
}
#Provides
#Singleton
static Context getContext(Application application){
return application.getApplicationContext();
}
}
AppComponent:
#Singleton
#Component(modules = {RetrofitModule.class,AppModule.class})
public interface AppComponent {
void inject(MainActivity mainActivity); //Error here.
#Component.Builder
interface Builder
{
AppComponent build();
#BindsInstance Builder appmod(Application application);
}
}
VolleyModule:
#Module
public abstract class VolleyModule {
#Provides
static RequestQueue getRequestQueue(Context context) {
return Volley.newRequestQueue(context);
}
}
MainActivity:
#Inject
RequestQueue requestQueue;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PokemonApplication.getAppComponent().inject(this);
VolleyModule has to be also declared in the list of modules in your Component
#Singleton
#Component(modules = {RetrofitModule.class,AppModule.class, VolleyModule.class})
I am confused about Dagger2 in Android.
I use two scope. #Singleton, #PerActivity
This is my Code. I simplyfy my code.
//ApplicationComponent.java
#Singleton
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
#Named("packageName") String packageName();
}
//ApplicationModule.java
#Module
public class ApplicationModule {
#Provides
#Singleton
public Context provideApplicationContext() {
return MyApplication.getContext();
}
#Provides
#Singleton
#Named("packageName")
public String providePackageName(Context context) {
return context.getPackageName();
}
}
//UserComponent.java
#PerActivity
#Component(modules = {UserModule.class})
public interface UserComponent {
void inject(MainActivity activity);
}
//UserModule.java
#Module
public class UserModule {
String packageName;
public UserModule(String packageName) {
this.packageName = packageName;
}
#Provides
#PerActivity
UserRepositoryImpl provideUserRepositoryImpl() {
return new UserRepositoryImpl(packageName);
}
}
for inject appVersion, packagename in UserModule
DaggerChatComponent.builder()
.userModule(new UserModule(getApplicationComponent().packageName()))
.build();
but it looks not great. how can i inject when use different Scope??
your ApplicationModule.java is correct
#Module
public class ApplicationModule {
private Application application;
public ApplicationModule(Application application){
this.application = application;
}
#Provides
#Singleton
Context provideContext(){
return application;
}
#Provides
#Singleton
#Named("packagename")
public String providePackageName(Context context) {
return context.getPackageName();
}
}
and it's component class is also right ApplicationComponent.java
#Singleton
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
#Named("packagename") String providepackagename();
}
but in the UserModule.java you need not pass the package name object , dagger's object graph does this for you.
#Module
public class UserModule {
public UserModule() {
}
#Provides
#PerActivity
UserRepositoryImpl provideUserRepositoryImpl(#Named("packagename") String packageName) {
return new UserRepositoryImpl(packageName);
}
}
and the next step is while writing the component class for this module add the application component as a dependency ie, your UserComponent.java looks like this
#PerActivity
#Component(dependencies = {ApplicationComponent.class},modules = {UserModule.class})
public interface UserComponent {
void inject(MainActivity mainActivity);
}
with the activity scope as PerActivity.lava
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface PerActivity {
}
with this example UserRepositoryImpl.java as
class UserRepositoryImpl {
private String packagename;
public UserRepositoryImpl(String packagename){
this.packagename = packagename;
}
String getPackagename(){
return packagename;
}
}
you can finally inject this in your activity.(MainActivity.java)
public class MainActivity extends AppCompatActivity {
#Inject
UserRepositoryImpl userRepository;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ApplicationComponent component=DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(getApplication())).build();
UserComponent userComponent=DaggerUserComponent.builder().applicationComponent(component).userModule(new UserModule()).build();
userComponent.inject(this);
Log.e("name"," "+userRepository.getPackagename());
}
}
How can I provide activity context in mainModule class ? Thanks! The code looks like this:
#Singleton
#Component(modules = {AndroidInjectionModule.class, AppModule.class, ActivityBuilder.class})
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(MvmApp app);
}
Activtity builder:
#Module
public abstract class ActivityBuilder {
#ContributesAndroidInjector(modules = {MainModule.class})
abstract MainActivity bindMainActivity();
}
And I have an appModule, and a module for each activity:
#Module
public class AppModule {
#Provides
#Singleton
#ApplicationContext
Context provideContext(Application application) {
return application;
}
#Provides
#Singleton
DataManager provideDataManager(AppDataManager appDataManager) {
return appDataManager;
}
#Provides
#DatabaseInfo
String provideDatabaseName() {
return "carDatabase";
}
#Provides
#Singleton
AppDataBase provideAppDatabase(#DatabaseInfo String dbName, #ApplicationContext Context context) {
return Room.databaseBuilder(context, AppDataBase.class, dbName)
.build();
}
#Provides
#Singleton
DbHelper provideDbHelper(AppDbHelper appDbHelper) {
return appDbHelper;
}
}
AppClass:
public class MvmApp extends Application implements HasActivityInjector {
#Inject
DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector;
#Override
public void onCreate() {
super.onCreate();
DaggerAppComponent.builder()
.application(this)
.build()
.inject(this);
}
#Override
public DispatchingAndroidInjector<Activity> activityInjector() {
return activityDispatchingAndroidInjector;
}
}
All my activities extends a base activity which inject the Dagger dependecies.
public abstract class BaseActivity extends AppCompatActivity implements MvpView {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidInjection.inject(this);
}
}
In mainModule I need to provide the context of the activity.
#Module
public class MainModule {
#Provides
MainMvpPresenter<MainMvpView> provideMainPresenter(
MainPresenter<MainMvpView> presenter) {
return presenter;
}
#Provides
CompositeDisposable provideCompositeDisposable() {
return new CompositeDisposable();
}
#Provides
CarAdapter provideCarAdapter( #ActivityContext Context context) {
return new CarAdapter(context);
}
}
The solution was:
#Module
public class MainModule {
#Provides
MainMvpPresenter<MainMvpView> provideMainPresenter(
MainPresenter<MainMvpView> presenter) {
return presenter;
}
#Provides
CompositeDisposable provideCompositeDisposable() {
return new CompositeDisposable();
}
#Provides
CarAdapter provideCarAdapter(MainActivity activity) {
return new CarAdapter(activity);
}
}
For people facing a similar issue, I've made a project with Kotlin, and the new android-dagger extension with a lengthy explanation on how things work over here: https://github.com/Obaied/BareBonesAndroidDagger