再次关于Android应用程序的多模块性

将整体式Android应用程序拆分为模块并不是什么新鲜事,这种组织代码的方式变得越来越普遍。会议上,我们已经讨论了有关在同事中使用模块的最佳实践的最佳话题我们已经收集了这种经验,并在我们的项目中对其进行了测试,我们希望分享得出的结论和建议。因此,本文对于那些只考虑分工的人和已经开始分工的人都是有用的。





开发人员通常会考虑使用多模块来加快构建时间。但这对我们来说不是最重要的事情。除了构建速度外,多模块化还提供了更严格的体系结构以及在项目之间重用功能的能力。



, . , , . Gradle - , Buck Bazel. , 300 .



. . - Android Wear. , .



, Java, , internal. : api + impl. , . .



, , Dagger, . , , . Kotlin, — , .



, , .





, , .



-, . , . . , AppComponent, ( KAPT) . , — , Gradle Android Gradle Plugin, , .



-, . . . , . Kotlin Multiplatform . , .



-, . . , , . , .



( , ) — . Maven-. , .



Git- . - .



: , , , .





:



  1. App- — , Feature-.



  2. Feature- — , , -. , , - (, UI- , , UI). Feature- API Feature- Core-.

    Feature- API , API . internal , API, «» Feature-. , . API Impl , , .

    .



  3. Core- — , , Feature-. , . Core- . : module-injector.



  4. Module-injector — , . , . .





API Impl Feature-, Feature- . internal- Kotlin.



Example- , App-. ( ) , . .



:



Module-Injector



, . , . , , . , , Dagger ( DI-). , :



interface ComponentHolder<C : BaseAPI, D : BaseDependencies> { 
    fun init(dependencies: D) 
    fun get(): C
    fun reset() 
} 

interface BaseDependencies

interface BaseAPI


. Feature- . ( , ) internal, .



- , , , Kotlin ( 2020-) module-injector. . .



, , — . : , . UI, , — .



Feature- , - , Core-. , :



, API Feature-. Feature-: :feature_purchase_api :feature_purchase_impl. API- , :module-injector. API-.



, . , .



ComponentHolder-:



object PurchaseComponentHolder : ComponentHolder<PurchaseFeatureApi, PurchaseFeatureDependencies> {
    private var purchaseComponentHolder: PurchaseComponent? = null

    override fun init(dependencies: PurchaseFeatureDependencies) {
        if (purchaseComponentHolder == null) {
            synchronized(PurchaseComponentHolder::class.java) {
                if (purchaseComponentHolder == null) {
                    purchaseComponentHolder = PurchaseComponent.initAndGet(dependencies)
                }
            }
        }
    }

    override fun get(): PurchaseFeatureApi {
        checkNotNull(purchaseComponentHolder) { "PurchaseComponent was not initialized!" }
        return purchaseComponentHolder!!
    }

    override fun reset() {
        purchaseComponentHolder = null
    }
}


:



  • .
  • init(), .
  • get(), API .
  • reset(), , .


. , .



PurchaseFeatureApi PurchaseFeatureDependencies , .



ComponentHolder Dagger-:



@Component(dependencies = [PurchaseFeatureDependencies::class], modules = [PurchaseModule::class])
@PerFeature
internal abstract class PurchaseComponent : PurchaseFeatureApi {

    companion object {
        fun initAndGet(purchaseFeatureDependencies: PurchaseFeatureDependencies): PurchaseComponent {
            return DaggerPurchaseComponent.builder()
                    .purchaseFeatureDependencies(purchaseFeatureDependencies)
                    .build()
        }
    }
}


initAndGet(), ComponentHolder. , Dagger . DI- .



, app :



@Module
class AppModule {

    @Singleton
    @Provides
    fun provideScannerFeatureDependencies(featurePurchase: PurchaseFeatureApi): ScannerFeatureDependencies {
        return object : ScannerFeatureDependencies {
            override fun dbClient(): DbClient = CoreDbComponent.get().dbClient()
            override fun httpClient(): HttpClient = CoreNetworkComponent.get().httpClient()
            override fun someUtils(): SomeUtils = CoreUtilsComponent.get().someUtils()
            override fun purchaseInteractor(): PurchaseInteractor = featurePurchase.purchaseInteractor()
        }
    }

    //      -   
    @Provides
    fun provideFeatureScanner(dependencies: ScannerFeatureDependencies): ScannerFeatureApi {
        ScannerFeatureComponentHolder.init(dependencies)
        return ScannerFeatureComponentHolder.get()
    }
    ...
}


provideScannerFeatureDependencies() ScannerFeatureDependencies, provideFeatureScanner() ComponentHolder- .



, app- . , . app- , . app- .



, .



, ComponentHolder reset(), . UI, reset() Lifecycle Observer- ( Activity, ):



public override fun onPause() {
   super.onPause()
           ...
   if (isFinishing) {
       AntitheftFeatureComponentHolder.reset()
   }
}


, , . get().



// get()  Feature-:
object PurchaseComponentHolder : ComponentHolder<PurchaseFeatureApi, PurchaseFeatureDependencies> {
    private var purchaseComponentHolder: PurchaseComponent? = null
...
    override fun get(): PurchaseFeatureApi {
        checkNotNull(purchaseComponentHolder) { "PurchaseComponent was not initialized!" }
        return purchaseComponentHolder!!
    }

    override fun reset() {
        purchaseComponentHolder = null
    }
// get()  app-:
//    @Singleton       Provider,  ,   get()  Dagger-
@Provides
   fun provideFeatureScanner(dependencies: ScannerFeatureDependencies): ScannerFeatureApi {
       ScannerFeatureComponentHolder.init(dependencies)
       return ScannerFeatureComponentHolder.get()
   }
}


, DI- app- (, Singleton Dagger). init() , , reset() .



API- — Provider<T> :



class GlobalNavigator @Inject constructor(
       //  Provider    get()                
       private val featureScanner: Provider<ScannerFeatureApi>,
       private val featureAntitheft: Provider<AntitheftFeatureApi>,
       private val context: Context
) : Navigator {
   ...
   featureScanner.get().scannerStarter().start(context) //  
   ...
}


UI



, API , . API , UI-, Activity, , View.



Activity API :



interface AntitheftStarter {
    fun start(context: Context)
}


Activity , Intent:



internal class AntitheftStarterImpl @Inject constructor() : AntitheftStarter {
    override fun start(context: Context) {
        val intent = Intent(context, AntitheftActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(intent)
    }
}


FragmentManager , API , . : Cicerone, Navigation Component FragmentManager.



, , . , .





Core-ui



UI- , , UI- . UIKit. , Application.



, theme.xml, (, Example-, , ). core-ui , , , . UIKit (api implementation) Feature-, UI. .



Core-strings



, , .



, , , : . . , . .



Core-native



C++-. JNI-, Java-. , SDK. , , ABI. , .






. , , . , , , .



, .




All Articles