Sai
Sai

Reputation: 15718

Dagger inject on superclass and sub-class

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

Answers (2)

gk5885
gk5885

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

Pushpendra
Pushpendra

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

Related Questions