Dagger 2 Third part Injection Android

2019-06-24 08:33发布

问题:

Hi im trying to figure out how to do a clean third party injection. I want to inject Otto bus properly into my services and activities. Iv seen that you can use inject on constructor, but since I dont have any constructor with Android, i wonder how I can then inject my bus.

Iv created a module which provides a new instance of the bus. Iv also created a component which has an interface for the Bus object.

But how can I get this injected and where should I initiate my graph?

Since the objectGraph from Dagger 1 is removed, i use the Dagger_.... component and create() in the application class, but how should I inject it into whatever activity or service?

Should I create the component in every onCreate and get the bus from there? Or is it possible to @Inject like Dagger 1? Please tell me because right now it seems much more clumpy and complicated than Dagger 1 way of doing it.

@Component(modules = EventBusModule.class)
@Singleton
public interface EventBus {
    Bus bus();
}

@Module
public class EventBusModule {

   @Provides
   @Singleton
   public Bus provideBus() {
       return new Bus(ThreadEnforcer.ANY);
   }
}

All i want to be able to do is:

public class WearService extends WearableListenerService {
    private static final String TAG = WearService.class.getSimpleName();

    @Inject
    protected Bus bus;

   @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        bus.register(this);
        return START_STICKY;
    }
}

I look at this example(https://github.com/LiveTyping/u2020-mvp) and see that its possible, but not sure how things is hanging together.

回答1:

It is quite usual to instantiate the Dagger component in the Application instance. Since you probably don't have a reference to your WearService from your Application class, you'll need to make the WearService ask your Application to provide the Bus.

You can do this in two ways:

  • By adding an inject(WearService wearService) method to your EventBus component:

    @Component(modules = EventBusModule.class)
    @Singleton
    public interface EventBus {
        Bus bus();
    
        void inject(WearService wearService);
    }
    

    You can now keep a reference to your Component in your Application:

    public class MyApplication extends Application {
    
        private EventBus mEventBusComponent;
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            mEventBusComponent = Dagger_EventBus.create();
        }
    
        public void inject(WearService wearService) {
            mEventBusComponent.inject(wearService);
        }
    }
    

    From your WearService, ask your Application to inject it:

    public class WearService extends WearableListenerService {
        private static final String TAG = WearService.class.getSimpleName();
    
        @Inject
        protected Bus bus;
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            ((MyApplication) getApplicationContext()).inject(this);
            bus.register(this);
            return START_STICKY;
        }
    }
    
  • By retrieving the Bus manually. Add a getter method for the EventBus component in the Application:

    public class MyApplication extends Application {
    
        private EventBus mEventBusComponent;
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            mEventBusComponent = Dagger_EventBus.create();
        }
    
        public EventBus getEventBusComponent() {
            return mEventBusComponent;
        }
    }
    

    Then, in your WearService, call the bus() method:

    public class WearService extends WearableListenerService {
        private static final String TAG = WearService.class.getSimpleName();
    
        private Bus bus;
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            bus = ((MyApplication) getApplicationContext()).getEventBusModule().bus();
            bus.register(this);
            return START_STICKY;
        }
    }
    

For injecting the Bus into classes you can instantiate, you can use constructor injection:

public class MyClass() {

  private final Bus mBus;

  @Inject
  public MyClass(final Bus bus) {
    mBus = bus;
  }
}

Since Dagger knows how to create a Bus instance (because of your @Provides method), Dagger will now also know how to create a MyClass instance, no @Provides method necessary. For example, this will work:

    public class WearService extends WearableListenerService {
        private static final String TAG = WearService.class.getSimpleName();

        @Inject
        protected Bus bus;

        @Inject
        protected MyClass myClass;

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            ((MyApplication) getApplicationContext()).inject(this);
            bus.register(this);
            return START_STICKY;
        }
    }

The MyClass instance will automatically be created for you, with the same instance of Bus (since it is marked as @Singleton).



回答2:

After some discususins with Niek regarding my question, I went to the source to find my answer. I asked on the github repo of dagger 2, and the answer can be found here:

https://github.com/google/dagger/issues/128#issuecomment-86702574

Its very deliberate and posts different solutions to my issue.