Dagger Android 使用解惑

Dagger已經(jīng)發(fā)展好幾年了凫佛,好多項(xiàng)目和開源項(xiàng)目都使用到了,但是也發(fā)生了好多次版本的更新孕惜。

學(xué)習(xí)肯定要學(xué)習(xí)最新的愧薛。之前老的也就不提了,最好學(xué)習(xí)新的時候忘記老的使用方式衫画,不然心中會有一萬只為什么奔騰毫炉。

我們以google 的示例項(xiàng)目“GithubBrowserSample”來學(xué)習(xí)。

幾個重要的類

@Singleton
@Component(
        modules = [
            AndroidInjectionModule::class,
            AppModule::class,
            MainActivityModule::class]
)
interface AppComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: Application): Builder
        fun build(): AppComponent
    }
    fun inject(githubApp: GithubApp)
}
@Module(includes = [ViewModelModule::class, TestModel::class])
class AppModule {
    @Singleton
    @Provides
    fun provideGithubService(): GithubService {
        return Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(LiveDataCallAdapterFactory())
                .build()
                .create(GithubService::class.java)
    }
    ...
}
@Suppress("unused")
@Module
abstract class ViewModelModule {
    @Binds
    @IntoMap
    @ViewModelKey(UserViewModel::class)
    abstract fun bindUserViewModel(userViewModel: UserViewModel): ViewModel
    ...
}
@Suppress("unused")
@Module
abstract class FragmentBuildersModule {
    @ContributesAndroidInjector
    abstract fun contributeRepoFragment(): RepoFragment

    @ContributesAndroidInjector
    abstract fun contributeUserFragment(): UserFragment

    @ContributesAndroidInjector
    abstract fun contributeSearchFragment(): SearchFragment
}

就這幾個類了削罩,把這個幾個類搞清楚了瞄勾,其它的也就沒問題了。
看到這幾個類弥激,有幾個新的東西:
1.AppComponent 的結(jié)構(gòu)
2.AndroidInjectionModule
3.@Binds @IntoMap
4.@ContributesAndroidInjector

好进陡,一個一個來

1.AppComponent
這個不用解析,記住就行了秆撮,記不住就copey來,就跟創(chuàng)建對象為什么要new 一樣换况,就是一個新的寫法职辨!

2.AndroidInjectionModule
這是表明對啥類型的組件進(jìn)行注入盗蟆,除了這個還有AndroidInjectionModule,看下代碼發(fā)現(xiàn)是對v4包里面的Fragment的包進(jìn)行操作舒裤,不信的可以自己看下代碼喳资。

3.@Binds @IntoMap
這是一種新的寫法,會把所有要注入的示例多加到一個集合里面腾供,并且key是可以自己定義的比如上面的

@Binds
    @IntoMap
    @ViewModelKey(UserViewModel::class)
    abstract fun bindUserViewModel(userViewModel: UserViewModel): ViewModel

而且使用了這種形式之后最后一定要加上

@Binds
    abstract fun bindViewModelFactory(factory: GithubViewModelFactory): ViewModelProvider.Factory

也就是把集合傳到那個實(shí)例里面仆邓,不然會 編譯不過的,記住就行了伴鳖。

4.@ContributesAndroidInjector
這個注解是針對要注入的四大組件节值,比如你要MainActivity實(shí)行注入

@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
    abstract fun contributeMainActivity(): MainActivity

對Service實(shí)行注入

@ContributesAndroidInjector
    abstract fun contributeService(): MyService

四大組件都是可以的,包含F(xiàn)ragment也是可以的
比如

@ContributesAndroidInjector
    abstract fun contributeRepoFragment(): RepoFragment

完了榜聂,這樣就完了搞疗,三分鐘。须肆。匿乃。
不,絕對不能三分鐘
來一波總結(jié)

這次改版后只要在Application中這樣寫

class GithubApp : Application(), HasActivityInjector {
    @Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>

    override fun onCreate() {
        super.onCreate()
        DaggerAppComponent.builder().application(this)
            .build().inject(this)
    }

    override fun activityInjector() = dispatchingAndroidInjector
}

Activity里面一句話就可以了

AndroidInjection.inject(activity)

是不是膜拜google大神豌汇。幢炸。。拒贱。

也就是這次把那些模板代碼也給省了宛徊,省了之后也就更難懂了,更難懂了也就更容易維護(hù)了柜思,這就是架構(gòu)岩调。

我把現(xiàn)在的Dagger 分兩類,一類是要注入的對象赡盘,一類是要被注入的對象的對象号枕。

  1. 要注入的對象,比如全局單例就直接加在AppComponent 中的Modules里面
@Singleton
@Component(
        modules = [
            AndroidInjectionModule::class,
            AppModule::class,
            MainActivityModule::class]
)
interface AppComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: Application): Builder
        fun build(): AppComponent
    }
    fun inject(githubApp: GithubApp)
}

AppModule

@Module(includes = [ViewModelModule::class, TestModel::class])
class AppModule {
    @Singleton
    @Provides
    fun provideGithubService(): GithubService {
        return Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(LiveDataCallAdapterFactory())
                .build()
                .create(GithubService::class.java)
    }

    @Singleton
    @Provides
    fun provideDb(app: Application): GithubDb {
        return Room
                .databaseBuilder(app, GithubDb::class.java, "github.db")
                .fallbackToDestructiveMigration()
                .build()
    }

    @Singleton
    @Provides
    fun provideUserDao(db: GithubDb): UserDao {
        return db.userDao()
    }

    @Singleton
    @Provides
    fun provideRepoDao(db: GithubDb): RepoDao {
        return db.repoDao()
    }
}

然后其他的不是單例的就放在AppModule的includes 里面陨享,其實(shí)也是可以放在AppComponent的modules 里面的比如把TestModel::class 放到AppModule同一個地方就可以了葱淳,最后生成的代碼就是類名不一樣,里面的代碼都是一樣的抛姑。(最好自己結(jié)合生成的代碼來理解)

@Singleton
@Component(
       modules = [
           AndroidInjectionModule::class,
           AppModule::class,
           MainActivityModule::class,
           TestModel::class]
)
interface AppComponent {
   @Component.Builder
   interface Builder {
       @BindsInstance
       fun application(application: Application): Builder

       fun build(): AppComponent
   }

   fun inject(githubApp: GithubApp)
}
@Module
class TestModel {
    @Provides
    fun provideDBUtil(): DBUtil {
        return DBUtil()
    }
}

效果都是一樣的赞厕。

2.要被注入的對象的對象
這一類就是四大組件和Fragment了
寫法就是@ContributesAndroidInjector 這個注解了
只要是要注入的就用這個注解寫
比如

@Suppress("unused")
@Module
abstract class MainActivityModule {
    @ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
    abstract fun contributeMainActivity(): MainActivity

}
@Suppress("unused")
@Module
abstract class FragmentBuildersModule {
    @ContributesAndroidInjector
    abstract fun contributeRepoFragment(): RepoFragment

    @ContributesAndroidInjector
    abstract fun contributeUserFragment(): UserFragment

    @ContributesAndroidInjector
    abstract fun contributeSearchFragment(): SearchFragment
}

Activity 包含了Fragment 所以把fragment的加在方法上面

@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])

放出來也一樣的
比如

@Suppress("unused")
@Module
abstract class MainActivityModule {
    @ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
    abstract fun contributeMainActivity(): MainActivity

    @ContributesAndroidInjector
    abstract fun contributeRepoFragment(): RepoFragment

}

我們就可以把多個Activity都用的放出來,只在一個Activity里面用的就放到@ContributesAndroidInjector里面去定硝,這樣結(jié)構(gòu)會比較清晰皿桑。

只要理解了這兩類對象,再遇到Dagger應(yīng)該就不會一萬個為什么了。這是個人的理解诲侮,難免有錯誤的镀虐,如果有希望指出,謝謝大家沟绪!

這次就先這樣了刮便,以后就知道怎么寫了,按照這兩類這樣寫就行了绽慈,下次再分析為什么要把ViewModel用注入的方式來注入恨旱,不能直接生產(chǎn)嗎?坝疼?下次再解析搜贤。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市裙士,隨后出現(xiàn)的幾起案子入客,更是在濱河造成了極大的恐慌,老刑警劉巖腿椎,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桌硫,死亡現(xiàn)場離奇詭異,居然都是意外死亡啃炸,警方通過查閱死者的電腦和手機(jī)铆隘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來南用,“玉大人膀钠,你說我怎么就攤上這事」妫” “怎么了肿嘲?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長筑公。 經(jīng)常有香客問我雳窟,道長,這世上最難降的妖魔是什么匣屡? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任封救,我火速辦了婚禮,結(jié)果婚禮上捣作,老公的妹妹穿的比我還像新娘誉结。我一直安慰自己,他們只是感情好券躁,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布惩坑。 她就那樣靜靜地躺著掉盅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪以舒。 梳的紋絲不亂的頭發(fā)上怔接,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天,我揣著相機(jī)與錄音稀轨,去河邊找鬼。 笑死岸军,一個胖子當(dāng)著我的面吹牛奋刽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播艰赞,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼佣谐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了方妖?” 一聲冷哼從身側(cè)響起狭魂,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎党觅,沒想到半個月后雌澄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡杯瞻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年镐牺,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魁莉。...
    茶點(diǎn)故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡睬涧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出旗唁,到底是詐尸還是另有隱情畦浓,我是刑警寧澤,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布检疫,位于F島的核電站讶请,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏电谣。R本人自食惡果不足惜秽梅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望剿牺。 院中可真熱鬧企垦,春花似錦、人聲如沸晒来。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至荧降,卻和暖如春接箫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背朵诫。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工辛友, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人剪返。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓废累,卻偏偏與公主長得像,于是被迫代替她去往敵國和親脱盲。 傳聞我的和親對象是個殘疾皇子邑滨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內(nèi)容