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 分兩類,一類是要注入的對象赡盘,一類是要被注入的對象的對象号枕。
- 要注入的對象,比如全局單例就直接加在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)嗎?坝疼?下次再解析搜贤。