来源博客: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 转成模块化有一些棘手,其中一些我试图经过上面的方法来解决,优势是深入的。若是您在模块中遇到任何障碍,请随时在下面说起它们,咱们能够一块儿讨论解决方案。
谢谢。