2017-12-06 16 views
7

Tôi đang cố gắng tìm ra cách ít lò hơi-y để triển khai ActivityModule được sử dụng trong tất cả các hoạt động ứng dụng của tôi. Đây là thiết lập hiện tại của tôi:Dagger 2 Đóng gópAndroidInjector cung cấp hoạt động cho mô-đun

ActivityModule:

@Module 
class ActivityModule(private val activity: Activity) { 

    @Provides @ActivityScope 
    fun providesActivity(): Activity = activity 

    @Provides @ActivityContext @ActivityScope 
    fun providesContext(): Context = activity 

    @Provides @ActivityContext @ActivityScope 
    fun providesLayoutInflater(): LayoutInflater = activity.layoutInflater 

    @Provides @ActivityContext @ActivityScope 
    fun providesResources(): Resources = activity.resources 

} 

AppActivityModule (cung cấp hoạt động cho AndroidInjectionModule)

@Module(subcomponents = [ 
     AppActivityModule.WelcomeActivityComponent::class 
    ]) 
    internal abstract class AppActivityModule { 

     @Binds 
     @IntoMap 
     @ActivityKey(WelcomeActivity::class) 
     abstract fun bindWelcomeActivityInjectorFactory(builder: WelcomeActivityComponent.Builder): AndroidInjector.Factory<out Activity> 

     @ActivityScope 
     @Subcomponent(modules = [(ActivityModule::class)]) 
     interface WelcomeActivityComponent : AndroidInjector<WelcomeActivity> { 
     @Subcomponent.Builder abstract class Builder : AndroidInjector.Builder<WelcomeActivity>() { 
      abstract fun activityModule(myActivityModule: ActivityModule): AndroidInjector.Builder<WelcomeActivity> 

      override fun seedInstance(instance: WelcomeActivity) { 
       activityModule(ActivityModule(instance)) 
      } 
     } 
    } 
} 

Những gì tôi muốn AppActivityModule được thay thế là:

@Module 
internal abstract class AppActivityModule { 
    @ContributesAndroidInjector(modules = [(ActivityModule::class)]) 
    abstract fun contributeWelcomeActivityInjector(): WelcomeActivity 
} 

Nhưng điều này, khá hiểu biết, mang lại cho tôi một lỗi /di/AppActivityModule_ContributeWelcomeActivityInjector.java:29: error: @Subcomponent.Builder is missing setters for required modules or subcomponents: [...di.modules.ActivityModule]

Câu hỏi của tôi là - có cách nào ít hơn để có được những gì tôi đang cố gắng làm không? Tôi biết về @Bind@BindsInstance (từ this answer) nhưng điều này dường như chỉ hoạt động nếu tôi có hoạt động theo mô-đun và ràng buộc loại hoạt động cụ thể mà tôi không muốn trong trường hợp này - Tôi muốn ActivityModule để làm việc với tất cả các hoạt động.

Trả lời

3

Một cách để giảm thiểu bản mẫu là tạo một ActivityModule chung và sau đó tạo một Mô-đun cụ thể nhỏ cho mỗi Hoạt động. Hãy tha thứ cho sự thiếu kinh nghiệm Kotlin của tôi, nhưng ở đây đi:

// Abstract class so you don't have to provide an instance 
@Module 
abstract class ActivityModule { 

    // No need for ActivityScope: You're always binding to the same Activity, so 
    // there's no reason to have Dagger save your Context instance in a Provider. 
    @Binds @ActivityContext 
    abstract fun providesContext(activity: Activity): Context 

    // This doesn't *have* to be in a companion object, but that way 
    // Android can do a static dispatch instead of a virtual method dispatch. 
    // If you don't need that, just skip the constructor arguments and make these 
    // normal methods and you'll be good to go. 
    @Module 
    companion object { 
     @JvmStatic @Provides @ActivityContext 
     fun providesLayoutInflater(activity: Activity): LayoutInflater = 
      activity.layoutInflater 

     @JvmStatic @Provides @ActivityContext 
     fun providesResources(activity: Activity): Resources = activity.resources 
    } 
} 

Và mô-đun của bạn:

@Module 
internal abstract class AppActivityModule { 

    @Module 
    internal interface WelcomeActivityModule { 
     // The component that @ContributesAndroidInjector generates will bind 
     // your WelcomeActivity, but not your Activity. So just connect the two, 
     // and suddenly you'll have access via injections of Activity. 
     @Binds fun bindWelcomeActivity(activity: WelcomeActivity) : Activity 
    } 

    @ContributesAndroidInjector(
     modules = [ActivityModule::class, WelcomeActivityModule::class]) 
    abstract fun contributeWelcomeActivityInjector(): WelcomeActivity 
} 

Lưu ý rằng mặc dù công trình này cho hoạt động, dịch vụ, BroadcastReceiver, và những người khác, bạn có thể không muốn để được như vậy nhanh chóng về nó cho Fragment. Điều này là do dagger.android xử lý phân cấp phân đoạn với các đoạn cha, vì vậy từ bên trong một thành phần con bạn có thể có quyền truy cập vào YourApplication, YourActivity, YourParentFragment và YourChildFragment và tất cả các thành phần của chúng. Nếu một cái gì đó trong YourChildFragmentComponent phụ thuộc vào một Fragment không đủ tiêu chuẩn, nó sẽ là mơ hồ cho dù nó thực sự muốn YourParentFragment hoặc YourChildFragment. Điều đó nói rằng, thiết kế này có ý nghĩa cho các hoạt động và một số mảnh vỡ, do đó, nó làm cho tinh thần để sử dụng nó (thận trọng).

+0

đối tượng đồng hành vẫn là một đối tượng, vì vậy những gì bạn nói về "công văn tĩnh thay vì gửi phương thức ảo" là không đúng sự thật. @JvmStatic tạo ra một phương thức tĩnh, gọi một phương thức cá thể trên đối tượng đồng hành. Không có cách nào để sử dụng tĩnh cung cấp trong một codebase chỉ Kotlin, theo như tôi biết. Hoặc bạn phải tạo mô-đun trong Java hoặc thành phần trong Java. – arekolek

+0

@arekolek Bạn nói đúng rằng đối tượng đồng hành được thực hiện trong Kotlin như một Singleton, và rằng một cuộc gọi cá thể là cần thiết trong Kotlin. (Mặt khác tôi không biết điều đó.) Mặt khác, Kotlin xử lý sự minh bạch 'tĩnh 'một cách minh bạch, trong khi Dagger sẽ thấy một phương thức' @ Provides' và giả sử rằng thành phần _each Component_ cần giữ một thể hiện của Module bất kể những gì Kotlin làm đằng sau hậu trường. Ngoài ra, nếu phương thức cá thể được tạo của Kotlin là 'final', nó sẽ _still_ dịch thành công văn tĩnh ngay cả khi nó trên một phương thức instance. (Tôi cần đào sâu vào bytecode.) –

+0

Hmm, có nghĩa là phương thức 'static' gọi phương thức' final' trên một đối tượng được giữ trong trường 'static final' có thể được tối ưu hóa bởi trình biên dịch, mặc dù đây là lần đầu tiên tôi nghe về nó. Các phương thức là 'final' theo mặc định trong Kotlin và chúng không thể được thực hiện' open' trong 'object', tôi đã kiểm tra bytecode và nó là' final' thực sự. Bạn có thể chỉ cho tôi một số tài liệu nói rằng không có cuộc gọi phương thức ảo nào xảy ra trong trường hợp này? – arekolek

Các vấn đề liên quan