Here is my simple app(mobile client for one of the banks in my country). Everything was good until I injected my MapService service to the MapActivity. I don't understand why it doesn't work because the same things work perfectly for MainActivity with MainService - configurations are very similar.
Here is hierarchy:
App
^ ^
MainActivity(may call Map) MapActivity
^ ^
MainFragment DepartmentFragment
Here are major components:
App
public class App extends DaggerApplication {
#Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerAppComponent.builder().application(this).create(this);
}
}
#Module
public abstract class ActivityBuilder {
#Binds
#IntoMap
#ActivityKey(MapActivity.class)
public abstract AndroidInjector.Factory<? extends Activity> bindMapActivity(MapActivityComponent.Builder builder);
#Binds
#IntoMap
#ActivityKey(MainActivity.class)
public abstract AndroidInjector.Factory<? extends Activity> bindMainActivity(MainActivityComponent.Builder builder);
}
#Component(modules = {
AndroidInjectionModule.class,
AppModule.class,
ActivityBuilder.class
})
public interface AppComponent extends AndroidInjector<App> {
#Component.Builder
public abstract class Builder extends AndroidInjector.Builder<App> {
#BindsInstance
public abstract Builder application(Application application);
public abstract AppComponent build();
}
}
#Module(subcomponents = {
MainActivityComponent.class,
MapActivityComponent.class
})
public class AppModule {
private static final String MTBANK_API_URL = "https://www.mtbank.by";
#Provides
public Context context(Application application) {
return application;
}
#Provides
public Retrofit xmlHttpAdapter() {
return new Retrofit.Builder()
.baseUrl(MTBANK_API_URL)
.client(new OkHttpClient())
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
}
#Provides
public MtbClient mtbClient(Retrofit retrofit) {
return retrofit.create(MtbClient.class);
}
}
Map Activity
public class MapActivity extends DaggerActivity implements OnMapReadyCallback {
#Inject
MapService mapService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
...
}
#Override
public void onMapReady(GoogleMap googleMap) {
....
}
}
#Subcomponent(modules = {MapActivityModule.class})
public interface MapActivityComponent extends AndroidInjector<MapActivity> {
#Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<MapActivity> {
}
}
#Module
public abstract class MapActivityModule {
#Provides
MapService mapService() {
return new MapService();
}
}
Main Activity
public class MainActivity extends DaggerActivity implements MainActivityContract.View, MainFragment.OnClickListener {
#Inject
MainService mapService;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
}
#Override
public void onDepartmensClick() {
...
}
}
#Subcomponent(modules = {MainActivityModule.class, MainFragmentsProvider.class})
public interface MainActivityComponent extends AndroidInjector<MainActivity> {
#Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<MainActivity> {
}
}
#Module(subcomponents = {DepartmentFragmentComponent.class, MainFragmentComponent.class})
public abstract class MainActivityModule {
#Provides
public static MainService mapService() {
return new MainService();
}
}
#Module
public abstract class MainFragmentsProvider {
#Binds
#IntoMap
#FragmentKey(DepartmentsFragment.class)
public abstract AndroidInjector.Factory<? extends Fragment> bindDepartmentsFragment(DepartmentFragmentComponent.Builder builder);
#Binds
#IntoMap
#FragmentKey(MainFragment.class)
public abstract AndroidInjector.Factory<? extends Fragment> bindMainFragment(MainFragmentComponent.Builder builder);
}
public class MainPresenter implements MainActivityContract.Presenter {
#Inject
public MainPresenter() {
}
}
public class MainService {
}
public interface MainActivityContract {
interface View {
}
interface Presenter {
}
}
Main Fragment
public class MainFragment extends DaggerFragment {
public interface OnClickListener {
void onDepartmensClick();
}
#BindView(R.id.departmens_button)
Button departmensButton;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.main_activity_fragment, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.bind(this, view);
...
}
}
#Subcomponent(modules = {MainFragmentModule.class})
public interface MainFragmentComponent extends AndroidInjector<MainFragment> {
#Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<MainFragment> {
}
}
#Module
public class MainFragmentModule {
}
Department Fragment
public class DepartmentsFragment extends DaggerFragment implements DepartmentFragmentContract.View {
#Inject
Context context;
#Inject
DepartmentFragmentContract.Presenter presenter;
#Inject
DepartmentService departmentService;
#Override
public void onViewCreated(View fragment, #Nullable Bundle savedInstanceState) {
super.onViewCreated(fragment, savedInstanceState);
...
}
}
#Subcomponent(modules = {DepartmentFragmentModule.class})
public interface DepartmentFragmentComponent extends AndroidInjector<DepartmentsFragment> {
#Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<DepartmentsFragment> {
}
}
public interface DepartmentFragmentContract {
interface View {
void displayData(RateInfo rateInfo);
void showMessage(String message);
void displayDepartments(List<Department> departments);
void fillInCities(List<String> cities);
void showAtMap(Department department);
void showDepartmentsRates(Department department);
}
interface Presenter {
void loadRatesInfo();
void showDepartmentLocation(Department department);
void showDepartmentsRates(Department department);
void filterDepartmentsByText(CharSequence text);
void filterDepartmentsByCityId(int id);
void resetCity();
}
}
#Module
public class DepartmentFragmentModule {
#Provides
public DepartmentFragmentContract.View view(DepartmentsFragment fragment) {
return fragment;
}
#Provides
public DepartmentFragmentContract.Presenter presenter(DepartmentPresenter rateInfoPresenter) {
return rateInfoPresenter;
}
#Provides
public DepartmentService myService() {
return new DepartmentService();
}
}
public class DepartmentPresenter implements DepartmentFragmentContract.Presenter {
private final DepartmentFragmentContract.View view;
private final MtbClient mtbApi;
#Inject
public DepartmentPresenter(DepartmentFragmentContract.View view,
MtbClient mtbClient) {
this.view = view;
this.mtbApi = mtbClient;
}
...
}
public class DepartmentService {
}
Here is the stack trace. I see the error message but cannot catch up why it says it.
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.slesh.mtbbank/com.slesh.mtbbank.ui.map.MapActivity}:
java.lang.IllegalStateException:
com.slesh.mtbbank.ui.map.MapActivityModule must be set
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2449)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2509)
at android.app.ActivityThread.access$1000(ActivityThread.java:153)
at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1373)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:5529)
at java.lang.reflect.Method.invoke(Native Method)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
Caused by: java.lang.IllegalStateException:
com.slesh.mtbbank.ui.map.MapActivityModule must be set
at
com.slesh.mtbbank.DaggerAppComponent$MapActivityComponentBuilder.build(DaggerAppComponent.java:220)
at
com.slesh.mtbbank.DaggerAppComponent$MapActivityComponentBuilder.build(DaggerAppComponent.java:211)
at
dagger.android.AndroidInjector$Builder.create(AndroidInjector.java:68)
at
dagger.android.DispatchingAndroidInjector.maybeInject(DispatchingAndroidInjector.java:79)
at
dagger.android.DispatchingAndroidInjector.inject(DispatchingAndroidInjector.java:104)
at dagger.android.AndroidInjection.inject(AndroidInjection.java:61)
at dagger.android.DaggerActivity.onCreate(DaggerActivity.java:36)
at com.slesh.mtbbank.ui.map.MapActivity.onCreate(MapActivity.java:34)
at android.app.Activity.performCreate(Activity.java:6303)
at
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2402)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2509)
at android.app.ActivityThread.access$1000(ActivityThread.java:153)
at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1373)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:5529)
at java.lang.reflect.Method.invoke(Native Method)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
Could somebody help me?
In your MapActivityModule.java.
Add static to mapService()
#Module
public abstract class MapActivityModule {
#Provides
static MapService mapService() {
return new MapService();
}
}
Related
My AppComponent
#Singleton
#Component(modules = {SplashModule.class})
public interface AppComponent {
void inject(SplashActivity splashActivity);//this is inject activity
}
Splash Module
#Module
public class SplashModule {
#Provides
#Singleton
static SplashInteract provideSplashInteract(){
return new SplashInteract();//instance interact
};
#Provides
#Singleton
SplashPresenter provideSplashPresenter(SplashInteract splashInteract){
return new SplashPresenter(splashInteract);//instance SplashPresenter
};
}
Splash Presenter
public class SplashPresenter implements ISplashContract.Presenter {
ISplashContract.View mView;
SplashInteract splashInteract;
public SplashPresenter(SplashInteract splashInteract) {
this.splashInteract =splashInteract;
}
public void bindView(ISplashContract.View mView) {
this.mView = mView;
}
#Override
public void attach() {
this.mView.startAnimation();//start splash animation
}
#Override
public void start(Activity activity) {
this.splashInteract.SplashScreenAnimation(activity);// add interact methods
}
}
Splash Activity
public class SplashActivity extends AppCompatActivity implements ISplashContract.View{
#Inject SplashPresenter splashPresenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
getAppComponent().inject(this);//call BaseApp DaggerAppComponent
splashPresenter.attach();
splashPresenter.bindView(this);
}
#Override
public void startAnimation() {
this.splashPresenter.start(this);
}
}
Base App
public class BaseApp extends Application {
private static AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
setUp();
}
private void setUp() {
appComponent = DaggerAppComponent.builder().build();//Call Component in BaseApp
}
public static AppComponent getAppComponent() {
return appComponent;
}
}
Hi Everyone
I am writing a project, I want to use dagger, but I am inexperienced at this. This code gives a NullPointerException error. I could not find what I am doing wrong.
I need help and I will be glad if those who know better than the dagger guide me
In your case, dagger will not know how to provide splashPresenter, either do a constructor Injection or define in the module how SplashPresenter should be created, and remove SpashPresenter from the Component. The module approach should be like so,
#Module
public class SplashModule {
ISplashContract.View mView;
public SplashModule(ISplashContract.View mView) {
this.mView = mView;//add SplashModule view
}
#Provides
#Singleton
public ISplashContract.View provideSplashPresenter(){
return mView;//set this view
}
#Provides
static SplashInteract provideSplashInteract(){
return new SplashInteract();//instance interact
};
#Provides
SplashPresenter provideSplashPresenter(ISplashContract.View mView, SplashInteract splashInteract){
return new SplashPresenter(mView, splashInteract);//instance SplashPresenter
};
}
And remove inject annotations from SplashPresenter and you will also have to change the signature for its constructor. You can optionally remove Singleton annotation from the code, if the presenter is not supposed to be singleton.
Updates based on comments
public class SplashModule {
#Provides
static SplashInteract provideSplashInteract(){
return new SplashInteract();//instance interact
};
#Provides
SplashPresenter provideSplashPresenter(SplashInteract splashInteract){
return new SplashPresenter(splashInteract);//instance SplashPresenter
};
}
public class SplashPresenter implements ISplashContract.Presenter {
ISplashContract.View mView;
SplashInteract splashInteract;
public SplashPresenter(SplashInteract splashInteract) {
this.splashInteract = splashInteract;
}
public void bindView(ISplashContract.View mView) {
this.mView = mView;
}
#Override
public void attach() {
this.mView.startAnimation();//start splash animation
}
#Override
public void start(Activity activity) {
this.splashInteract.SplashScreenAnimation(activity);// add interact methods
}
}
public class SplashActivity extends AppCompatActivity implements ISplashContract.View{
#Inject SplashPresenter splashPresenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
getAppComponent().inject(this);//call BaseApp DaggerAppComponent
splashPresenter.bind("the view you want to bind")
splashPresenter.attach();
}
#Override
public void startAnimation() {
this.splashPresenter.start(this);
}
}```
Make sure that you declare your BaseApp in AndroidManifest :
<application
android:name=".fullPathTo.BaseApp"
...
I am trying to implement new architecture (MVVM + RxJava2 + Dagger2 + Retrofit) in my existing project. I have set up whole above architecture and tested on HomeActivity. Dependencies injected in HomeViewModel. So Now I was trying to inject dependencies same as HomeViewModel in a FollowingViewModel of FollowingFragment which is a container Fragment of HomeActivity.But injected dependencies always return null(Not Initiziling).
I am following this project riggaroo/android-arch-components-date-countdown to Inject dependencies but in this sample, only activities are used no fragment. So I don't know what is happening and who to inject deps in multiple ViewModels.
Here is code for some important classes to understand:
AppApplication.class
public class AppApplication extends MultiDexApplication implements HasActivityInjector {
#Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
#Override
public void onCreate() {
...........................
AppInjector.init(this)
..........................
}
#Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingAndroidInjector;
}
}
AppInjector.class
public class AppInjector {
private AppInjector() {
}
public static void init(AppApplication appApplication) {
DaggerAppComponent.builder()
.application(appApplication)
.build()
.inject(appApplication);
appApplication
.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
handleActivity(activity);
}
});
}
private static void handleActivity(Activity activity) {
if (activity instanceof HasSupportFragmentInjector) {
AndroidInjection.inject(activity);
}
if (activity instanceof FragmentActivity) {
((FragmentActivity) activity).getSupportFragmentManager()
.registerFragmentLifecycleCallbacks(
new FragmentManager.FragmentLifecycleCallbacks() {
#Override
public void onFragmentCreated(FragmentManager fm, Fragment f,
Bundle savedInstanceState) {
if (f instanceof Injectable) {
AndroidSupportInjection.inject(f);
}
}
}, true);
}
}
}
AppComponent.class
#Singleton
#Component(modules = {AndroidSupportInjectionModule.class,ActivityBuilderModule.class, AppModule.class, NetworkModule.class})
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(AppApplication application);
AppComponent build();
}
void inject(AppApplication app);
AppModule.class
#Module(includes = { ViewModelModule.class})
public class AppModule {
#Provides
Context provideContext(AppApplication application) {
return application.getApplicationContext();
}
}
ActivityBuilderModule.class
#Module
public abstract class ActivityBuilderModule {
#ContributesAndroidInjector(modules = FragmentBuildersModule.class)
abstract HomeActivity bindHomeActivity();
}
FragmentBuildersModule.class
#Module
public abstract class FragmentBuildersModule {
#ContributesAndroidInjector
abstract FollowingListFragment contributeFollowingListFragment();
}
ViewModule.class
#Module
public abstract class ViewModelModule {
#Binds
#IntoMap
#ViewModelKey(FollowingViewModel.class)
abstract ViewModel bindFollowingViewModel(FollowingViewModel followingViewModel);
#Binds
#IntoMap
#ViewModelKey(HomeViewModel.class)
abstract ViewModel bindHomeViewModel(HomeViewModel homeViewModel);
#Binds
abstract ViewModelProvider.Factory bindViewModelFactory(MyViewModelFactory factory);
}
NetworkModule.class
#Module
public class NetworkModule {
public NetworkModule(){}
#Provides
#Singleton
CompositeDisposable getCompositeDisposable() {
return new CompositeDisposable();
}
#Provides
#Singleton
Retrofit provideCall() {
// OKHttps and Retrofit code...
}
#Provides
#Singleton
#SuppressWarnings("unused")
public ApiCallInterface providesNetworkService(
Retrofit retrofit) {
return retrofit.create(ApiCallInterface.class);
}
#Provides
#Singleton
#SuppressWarnings("unused")
public Repository providesService(
ApiCallInterface networkService) {
return new Repository(networkService);
}
}
MyViewModelFactory.class
#Singleton
public class MyViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;
#Inject
public MyViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
this.creators = creators;
}
#SuppressWarnings("unchecked")
#Override
public <T extends ViewModel> T create(Class<T> modelClass) {
Provider<? extends ViewModel> creator = creators.get(modelClass);
if (creator == null) {
for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
if (modelClass.isAssignableFrom(entry.getKey())) {
creator = entry.getValue();
break;
}
}
}
if (creator == null) {
throw new IllegalArgumentException("unknown model class " + modelClass);
}
try {
return (T) creator.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
This class is used to create Instances of all viewModels. I have debugged and found only HomeViewModel instance is creating.
Now I have created HomeViewModel which is called from HomeActivity. Which is working fine. Now same implementaion is done in FollowingFragment but doesn't work. Let me show you how I have initialized FollowViewModel from FollowingListFragment.class
public class FollowingListFragment extends BaseFragment implementsInjectable {
#Inject
MyViewModelFactory myViewModelFactory;
private FollowingViewModel followingViewModel;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity();
followingViewModel = ViewModelProviders.of(this, plownsViewModelFactory)
.get(FollowingViewModel.class);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_following_list, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
followingViewModel.getFollowings(id,curser);
}
}
Here is FollowingViewModel.class
public class FollowingViewModel extends ViewModel {
#Inject
Repository service;
#Inject
CompositeDisposable subscriptions;
#Inject
public FollowingViewModel() {
}
/*void setService(Repository service){
this.service = service;
}*/
void getFollowings(String id,String curser) {
if(service!=null) { **//HERE SERVICE RETURNS NULL**
Disposable subscription = service.getFollowings(id, curser, new IResponseCallback<FollowingResponse.FollowingResult>() {
#Override
public void onSuccess(FollowingResponse.FollowingResult followingResult) {
}
#Override
public void onError(Throwable throwable) {
}
});
subscriptions.add(subscription);
}else {
Log.d("FollowViewModel", "Service is null " );
}
}
Here is HomeActivity and HomeViewModel class code which is working fine.
HomeActivity.class
public class HomeActivity extends BaseActivity implements HasSupportFragmentInjector, Injectable {
#Inject
DispatchingAndroidInjector<Fragment> supportFragmentInjector;
#Inject
MyViewModelFactory viewFactory;
HomeViewModel homeViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
homeViewModel = ViewModelProviders.of(this,viewFactory).get(HomeViewModel.class);
homeViewModel.getFollowings("xyx",null);
}
#Override
public AndroidInjector<Fragment> supportFragmentInjector() {
return supportFragmentInjector;
}
}
HomeViewModel.class
public class HomeViewModel extends ViewModel {
#Inject
Repository service;
#Inject
CompositeDisposable subscriptions;
#Inject
public HomeViewModel() {
}
void getFollowings(String id,String curser) {
if(service!=null) { **// Returing null service**
}
}else {
Log.d("FollowViewModel", "Service is null " );
}
}
}
I have an application (module + component) where
#Singleton
#Component(modules = AppModule.class)
public interface AppComponent {
void inject(App app);
Serializer getSerializer();
ListOfCallingLists getListOfCallingLists();
Context getContext();
App getApp();
}
And
#Module
public class AppModule {
private final App app;
public AppModule(App app) {
this.app = app;
}
#Provides
Serializer provideSerializer() {
return new BinarySerializer();
}
#Provides
Context provideContext() {
return app;
}
#Provides
App provideApp() {
return app;
}
}
And
#Singleton
public class ListOfCallingLists implements Serializable {
...
#Inject
public ListOfCallingLists(Context context,
Serializer serializer) {
this.serializer = serializer;
...
}
}
And App is the application, I registered it in manifest:
public class App extends Application {
private AppComponent appComponent;
public static App get(Context context) {
return (App) context.getApplicationContext();
}
#Override
public void onCreate() {
super.onCreate();
if (appComponent == null)
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
appComponent.inject(this);
}
public AppComponent getComponent() {
return appComponent;
}
}
And finally the activity:
public class CallListsActivity extends AppCompatActivity {
#Inject
ListOfCallingLists list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
}
#Override
public void onPostCreate(#Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// list here is null why?
}
}
In your AppComponent you need to add:
void inject(CallListsActivity callListActivity);
And in your CallListsActivity's onCreate() you need to tell how is your CallListsActivity injected.
For example, build your AppComponent and inject the activity, or you can use the new android injector: https://google.github.io/dagger/android.html
I am trying to inject my MainActivity into the Fragment. I have an Interface that is implemented in my MainActivity that will listen to events from the Fragment. So I want to Inject the MainActivity and call the event listener on it.
I have tried doing the following but has failed to do so. Just displaying the code snippets.
interface
public interface RecipeItemListener {
void onRecipeItem();
}
MainActivity that implements the interface
public class MainActivity extends AppCompatActivity implements RecipeItemListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.add(R.id.main_fragment_container, RecipeListView.newInstance(), RecipeListView.TAG)
.commit();
}
}
#Override
public void onRecipeItem() {
Timber.d("onRecipeItem");
}
}
My Module that provides the MainActivity
#Module
public class RecipeListModule {
private MainActivity mainActivity;
public RecipeListModule(MainActivity mainActivity) {
this.mainActivity = mainActivity;
}
#RecipeListScope
#Provides
public RecipeItemListener providesRecipeListMainActivity() {
return mainActivity;
}
}
My main Component
#Singleton
#Component(modules = {
AndroidModule.class,
NetworkModule.class})
public interface BusbyBakingComponent {
RecipeListComponent add(RecipeListModule recipeListModule);
}
My SubComponent
#RecipeListScope
#Subcomponent(modules = {RecipeListModule.class})
public interface RecipeListComponent {
void inject(RecipeListView target);
}
My Application class
public class BusbyBakingApplication extends Application {
private BusbyBakingComponent applicationComponent;
private RecipeListComponent recipeListComponent;
#Override
public void onCreate() {
super.onCreate();
applicationComponent = createApplicationComponent();
}
public BusbyBakingComponent createApplicationComponent() {
return DaggerBusbyBakingComponent.builder()
.networkModule(new NetworkModule())
.androidModule(new AndroidModule(BusbyBakingApplication.this))
.build();
}
public BusbyBakingComponent getApplicationComponent() {
return applicationComponent;
}
public RecipeListComponent createRecipeListComponent(MainActivity activity) {
recipeListComponent = applicationComponent.add(new RecipeListModule(activity));
return recipeListComponent;
}
public void releaseRecipeListComponent() {
recipeListComponent = null;
}
}
And in My fragment this is how I am trying to inject:
#Inject MainActivity mainActivity;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((BusbyBakingApplication)getActivity().getApplication())
.createRecipeListComponent((MainActivity)getActivity())
.inject(RecipeListView.this);
}
I keep getting the following error:
Error:(14, 8) error: [me.androidbox.busbybaking.di.RecipeListComponent.inject(me.androidbox.busbybaking.recipieslist.RecipeListView)] me.androidbox.busbybaking.recipieslist.MainActivity cannot be provided without an #Inject constructor or from an #Provides- or #Produces-annotated method.
me.androidbox.busbybaking.recipieslist.MainActivity is injected at
me.androidbox.busbybaking.recipieslist.RecipeListView.mainActivity
me.androidbox.busbybaking.recipieslist.RecipeListView is injected at
me.androidbox.busbybaking.di.RecipeListComponent.inject(target)
Many thanks for any suggestions.
If you have a look at your module
#RecipeListScope
#Provides
public RecipeItemListener providesRecipeListMainActivity() {
return mainActivity;
}
You provide the interface (which is good) and not MainActivity (the implementation).
Since you request MainActivity
#Inject MainActivity mainActivity;
You receive this error:
MainActivity cannot be provided [...]
because you only provide RecipeItemListener.
Switch your code from requiring MainActivity in RecipeListView to
#Inject RecipeItemListener recipeListener;
and it should work, if the rest of your setup is correct.
You can access activity in Fragment using getActivity() and cast it to your interface listener like this
((RecipeItemListener)getActivity()).doSomethingOnListener()
much simpler, without any unnecessary injections
I want to add an activity as a dependency for one of my classes
class ViewHandler{
#inject public ViewHandler(Myactivity myactivity){
this.activity = myactivity;
}
}
how can I do this without being obstructed by the Activity life cycle
You need to use subscoped components with modules for this.
#Singleton
#Component(modules={SomethingModule.class})
public interface ApplicationComponent {
Something something();
}
#Module
public class SomethingModule {
#Provides
#Singleton
public Something something() {
return new Something();
}
}
#ActivityScope
#Component(dependencies={ApplicationComponent.class}, modules={MyActivityModule.class})
public interface MyActivityComponent extends ApplicationComponent {
ViewHandler viewHandler();
void inject(Myactivity myActivity);
}
#Module
public class MyActivityModule {
private Myactivity myActivity;
public MyActivityModule(Myactivity myActivity) {
this.myActivity = myActivity;
}
#Provides
public Myactivity myActivity() {
return myActivity;
}
#Provides
#ActivityScope
public ViewHandler viewHandler(Myactivity myActivity) {
return new ViewHandler(myActivity);
}
}
public class CustomApplication extends Application {
ApplicationComponent applicationComponent;
#Override
public void onCreate() {
super.onCreate();
applicationComponent = DaggerApplicationComponent.create();
}
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
}
public class Myactivity extends AppCompatActivity {
MyActivityComponent myActivityComponent;
#Inject
ViewHandler viewHandler;
#Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
CustomApplication customApp = (CustomApplication)getApplicationContext();
this.myActivityComponent = DaggerMyActivityComponent.builder()
.applicationComponent(customApp.getApplicationComponent())
.myActivityModule(new MyActivityModule(this))
.build(); //preserve the state of your dependencies in onSaveInstanceState();
myActivityComponent.inject(this);
}
}
EDIT: Another option is #Subcomponent annotation
#Singleton
#Component(modules={SomethingModule.class})
public interface ApplicationComponent {
Something something();
MyActivityComponent newMyActivityComponent(MyActivityModule myActivityModule);
}
#ActivityScope
#Subcomponent(modules={MyActivityModule.class})
public interface MyActivityComponent {
ViewHandler viewHandler();
void inject(Myactivity myActivity);
}
public class Myactivity extends AppCompatActivity {
MyActivityComponent myActivityComponent;
#Inject
ViewHandler viewHandler;
#Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
CustomApplication customApp = (CustomApplication)getApplicationContext();
this.myActivityComponent = customApp.getApplicationComponent()
.newMyActivityComponent(new MyActivityModule(this));
myActivityComponent.inject(this);
}
}