dagger
dagger copied to clipboard
Poor error messaging with Subclass and Extended Graph
update2: turns out I forgot about a subclass! but all the error messaging and behavior seen in comments 1 and 2 were super confusing.
update: The following seems to be a result of having a no-args constructor on TabAdapter, once I add arguments it crashes. See second comment for details.
I'm seeing a weird bug with @Singleton in one of my extended graphs (an activity containing a fragment).
If I provide an Adapter with a @Provides function, I get multiple instances of the Adapter:
@Provides @Singleton TabAdapter provideTabAdapter() {
Timber.d("vmi provide Tab Adapter");
return new TabAdapter();
}
when logging the hashcode and constructor, you'll see the objectgraph is the same, but the TabAdapter is constructed twice (also notice provide Tab Adapter is only logged once, so maybe the first time dagger is directly creating from the contructor?):
02-27 14:45:06.844 D/DashApp﹕ vmi injecting objectGraph: 1107898536
02-27 14:45:06.844 D/TabAdapter﹕ vmi tabadapter constructor
02-27 14:45:06.844 D/VenueActivity﹕ vmi activity adapter: 1109289504
02-27 14:45:07.253 D/DashApp﹕ vmi injecting objectGraph: 1107898536
02-27 14:45:07.255 D/VenueModule﹕ vmi provide Tab Adapter
02-27 14:45:07.259 D/TabAdapter﹕ vmi tabadapter constructor
02-27 14:45:07.260 D/TabFragment﹕ vmi fragment adapter: 1108907360
if instead if use constructor injection, @Singleton works fine:
@Singleton
public class TabAdapter extends BaseAdapter {
@Inject
public TabAdapter() {
Timber.d("vmi tabadapter constructor");
}
// ...
}
and you'll see the hashcodes are now the same and the constructor is only called once:
02-27 14:47:00.834 D/DashApp﹕ vmi injecting objectGraph: 1109771688
02-27 14:47:00.835 D/TabAdapter﹕ vmi tabadapter constructor
02-27 14:47:00.836 D/VenueActivity﹕ vmi activity adapter: 1108594168
02-27 14:47:01.344 D/DashApp﹕ vmi injecting objectGraph: 1109771688
02-27 14:47:01.345 D/TabFragment﹕ vmi fragment adapter: 1108594168
Shouldn't these 2 methods have the same expected behavior?
So after some more tinkering I've noticed that the above was happening because of the no args constructor that TabAdapter has which dagger was using to create an instance with. I haven't been able to reproduce the above again, instead I get crashes.
My setup is as follows:
ApplicationModuleis the base ApplicationObjectGraphVenueModuleis the activity scope module, correctly defined withaddsToVenueActivityhasTabFragmentas a child.
VenueModule annotation:
@Module(
injects = {
TabFragment.class,
VenueActivity.class
},
addsTo = AppModule.class,
)
public class VenueModule {
@Provides @Singleton TabAdapter provideTabAdapter() {
// if was is a no-args constructor, dagger still finds it and creates an instance
return new TabAdapter("asdfads");
}
}
My VenueActivity is as follows:
private ObjectGraph objectGraph;
@Inject SessionManager sessionManager; // this comes from ApplicationModule
@Inject TabAdapter mAdapter; // this comes from VenueModule
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
objectGraph = DashApp.get(this).getObjectGraph().plus(new VenueModule(this));
objectGraph.inject(this);
// ...
}
TabFragment also uses the VenueActivity extended ObjectGraph to inject itself in onActivityCreated
This is the weird part:
- All injection works fine on the
Fragment - All injection passes compile time validation
- If I try to inject anything from VenueModule into VenueActivity, it crashes and doesn't see the
@Providesfunctions:me.dashwith.ui.venue.tab.TabAdapter has no injectable members. Do you want to add an injectable constructor? required by class me.dashwith.ui.venue.VenueActivity - If I remove the injections from
VenueModuleinVenueActivity, things work fine
So why wouldn't the Activity be able to inject itself if the Fragment injection works fine? Is the objectgraph not ready if I inject with it right away? This doesn't seem to make sense...
Wow. Turns out I had a subclass of VenueActivity, DemoVenueActivity, which I forgot to list under injects. I'm not sure if messaging can be improved in this case? or why that subclass causes problems?