來源博客:Wang Jie's Blog
本文連接:http://blog.wangjiegulu.com/2018/02/13/writing_a_modular_project_on_android
版權聲明:本博客全部文章除特別聲明外,均採用 CC BY 4.0 CN協議 許可協議。轉載請註明出處。
html
原文:https://medium.com/mindorks/writing-a-modular-project-on-android-304f3b09cb37java
當咱們在 Android Studio 上建立一個新的項目時,自帶一個 app
module。這時咱們大多數人編寫整個應用的地方。每次點擊 run
按鈕都會觸發咱們整個全部 module 上的 gradle 構建,並檢查全部文件是否有變化。這就是爲何 gradle 構建會在更大的應用程序上花費 10分鐘的時間,而且減慢開發者的輸出。react
要解決這個問題,複雜的應用程序,如 Uber 決定對它們的應用程序進行模塊化並從中得到了不少。下面是試用模塊化項目的一些優點:android
因爲上述優點,當我剛開始Posts這個應用時,我就在始終堅持使用模塊化方法。對此,Android 團隊已經給咱們提供了一些工具,可是我確實遇到了一些障礙,一下是我學習到的內容:git
你的應用程序是流程集構成的,好比,Google Play 有應用詳情流,它包含了簡要,描述詳情,應用截圖,評論活動等。github
全部這些均可以歸爲同一模塊 —— app-details
。數據庫
你的應用會包含多個相似流程的模塊,有 authentication
, settings
, on-boarding
等等。固然還有一些不須要UI元素呈現的模塊如 —— notifications
, analytics
, first-fetch
等等。這些模塊包含與流程有關的 activities, repositories, entities和依賴注入相關東西。api
可是這些模塊中老是有一些共同的功能和工具。這就是爲何你須要一個 core 模塊。app
Core
模塊是一個你項目中簡單的 module 庫。core 庫能夠(除其它外),框架
核心(core
)模塊的其中一個職責是爲你的功能(feature
)模塊提供外部依賴。這使得很容易實如今你的 feature
模塊中共享相同版本的庫。只須要在你的 core
模塊的 dependencies 中使用 api
,這樣你就能在全部 feature
模塊中使用它們。
dependencies { api fileTree(include: ['*.jar'], dir: 'libs') api deps.support.appCompat api deps.support.recyclerView api deps.support.cardView api deps.support.support api deps.support.designSupport api deps.android.lifecycleExt api deps.android.lifecycleCommon api deps.android.roomRuntime api deps.android.roomRx api deps.kotlin.stdlib api deps.reactivex.rxJava api deps.reactivex.rxAndroid api deps.google.dagger kapt deps.google.daggerProcessor api deps.square.picasso api deps.square.okhttpDownloader api deps.square.retrofit api deps.square.okhttp api deps.square.gsonConverter api deps.square.retrofitRxAdapter implementation deps.facebook.stetho implementation deps.facebook.networkInterceptor testApi deps.test.junit androidTestApi deps.test.testRunner androidTestApi deps.test.espressoCore }
有種依賴的可能性是隻有對 feature-a
模塊有用,可是在 feature-b
中無用。對於這種狀況,我推薦在你的 core 的依賴中使用 api
,由於 proguard 注意到而不會包含在 feature-b
instant app 中。
這個困擾我挺久的時間。咱們但願把咱們的數據庫定義到 core
模塊中,由於它是咱們應用程序要共享的通用的功能。爲了讓 Room 工做,你須要一個包含了全部 entity 類的數據庫文件。
@Database(entities = [Post::class, User::class, Comment::class], version = 1,exportSchema = false) abstract class PostDb : RoomDatabase() { abstract fun postDao(): PostDao abstract fun userDao(): UserDao abstract fun commentDao(): CommentDao }
可是,如上面提到的,咱們的 entity 類是被定義在 feature
模塊中,並且 core
模塊不能去訪問它們。這是我碰到障礙的地方,通過一番思考後,你作了一件最棒的事,尋求 Yigit 的幫助。
Yigit 闡明瞭觀點,你必需要在每一個 feature
模塊中都建立一個新的 db 文件,而後每一個模塊一個數據庫。
這有幾個好處:
缺點:
注意:爲了 Room 的註解可以工做,不要忘記在你的 feature
模塊中增長下面依賴
kapt "android.arch.persistence.room:compiler:${versions.room}"
一樣的問題 Dagger 也遇到了。個人 core 模塊中的 application 類不能訪問和初始化我 feature
模塊中的組件。這是從屬組件完美的用例。
你的 core 組件定義了它想要暴露給依賴組件的依賴關係
@Singleton @Component(modules = [AppModule::class, NetworkModule::class, StorageModule::class, ImageModule::class]) interface CoreComponent { fun context(): Context fun retrofit(): Retrofit fun picasso(): Picasso fun sharedPreferences(): SharedPreferences fun scheduler(): Scheduler }
您的模塊組件將 CoreComponent
定義爲依賴項,並使用傳遞的依賴
@ListScope @Component(dependencies = [CoreComponent::class], modules = [ListModule::class]) interface ListComponent { fun inject(listActivity: ListActivity) } @Module @ListScope class ListModule { /*Uses parent's provided dependencies like Picasso, Context and Retrofit*/ @Provides @ListScope fun adapter(picasso: Picasso): ListAdapter = ListAdapter(picasso) @Provides @ListScope fun postDb(context: Context): PostDb = Room.databaseBuilder(context, PostDb::class.java, Constants.Posts.DB_NAME).build() @Provides @ListScope fun postService(retrofit: Retrofit): PostService = retrofit.create(PostService::class.java) }
我爲個人功能的全部組件建立了一個單例 holder。這個 holder 用於建立,維護和銷燬個人 component 實例。
@Singleton object PostDH { private var listComponent: ListComponent? = null fun listComponent(): ListComponent { if (listComponent == null) listComponent = DaggerListComponent.builder().coreComponent(CoreApp.coreComponent).build() return listComponent as ListComponent } fun destroyListComponent() { listComponent = null } }
注意:爲了 Dagger 的註解可以工做,不要忘記在你的 feature
模塊中增長下面依賴
kapt "com.google.dagger:dagger-compiler:${versions.dagger}"
儘管把你的單獨的 application 轉成模塊化有一些棘手,其中一些我試圖經過上面的方法來解決,優勢是深入的。若是您在模塊中遇到任何障礙,請隨時在下面說起它們,咱們能夠一塊兒討論解決方案。
謝謝。