Reputation: 15718
BaseFragment class
open class BaseFragment : Fragment() {
@Inject lateinit var apiManager: ApiManager
@Inject lateinit var eventBus: EventBus
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
App.getInstance().component.inject(this)
}
override fun onStop() {
eventBus.unreg(this)
super.onStop()
}
override fun onStart() {
super.onStart()
eventBus.reg(this)
}
}
RoomsFragment class
class RoomsFragment : BaseFragment() {
@Inject lateinit var roomAdapter: RoomsAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
App.getInstance().component.inject(this)
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater?.inflate(R.layout.fragment_rooms_fragment_new, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
recyclerView.adapter = roomAdapter //This line throws null or lateinit property roomAdapter has not been initialized
}
}
AdapterModule class
@Module(includes = AppModule.class)
public class AdapterModule {
@Provides //App module has EventBus so i included it in Module
RoomsAdapter provideRoomsAdapter(EventBus eventBus) {
return new RoomsAdapter(eventBus);
}
}
AppComonent class
@Singleton
@Component(modules = {AppModule.class, AdapterModule.class})
public interface ApplicationComponent {
void inject(ApiManager apiManager);
void inject(BaseFragment baseFragment);
}
As you can see i'm trying to Inject objects in both superclass and sub class, but it is not not working as expected. BaseFragment
Injected objects work find but RoomsFragment
Injection fail. Any solution ?
Fix:
I forgot to add interface for sub-classRoomsFragment
in ApplicationComponent. Since its superclass BaseFragment
interface was present it was not throwing any error at compile time.
@Singleton
@Component(modules = {AppModule.class, AdapterModule.class})
public interface ApplicationComponent {
void inject(RoomsFragment roomsFragment);
void inject(ApiManager apiManager);
void inject(BaseFragment baseFragment);
}
Upvotes: 1
Views: 2718
Reputation: 3762
The documentation of members injection methods in the @Component
documentation describes the relevant behavior.
It looks like you are trying to inject members of RoomsFragment
. By adding a method that accepts RoomsFragment
, you will inject the @Inject
members of RoomsFragment
and any supertype (in this case `BaseFragment).
On the other hand, if you invoke a members injection method that accepts BaseFragment
, you will inject the @Inject
members of BaseFragment
, but not any members of any subtype. For that reason, it is almost never a good idea to define a members injection method for an abstract type.
In the original question, this is complicated by the fact that all of the members injection methods are defined as overloads of each other. This means that you will get different injection behavior for a given type depending on how the overload is resolved. See Effective Java 2: Item 41 for more background on why these overloads are error-prone.
It is also worth noting that in the original code sample there is a members injection method for ApiManager
, but that type is injected as an instance into BaseFragment
. Injecting members resolves dependencies transitively, so there is no need to define any method for ApiManager
on the component.
So, in order to inject all of the members of RoomsFragment
(declared and inhertied), just define one members injection method for RoomsFragment
:
@Singleton
@Component(modules = {AppModule.class, AdapterModule.class})
public interface ApplicationComponent {
void inject(RoomsFragment roomsFragment);
}
Upvotes: 5
Reputation: 2819
Try this:
@Singleton
@Component(modules = {AppModule.class, AdapterModule.class})
public interface ApplicationComponent {
void inject(ApiManager apiManager);
void inject(BaseFragment baseFragment);
void inject(RoomsFragment roomsFragment);
}
Upvotes: 1