记录一下--关于Hilt在多模块开发中的使用

        接触Android以来,也没有使用过什么特别高端的技术,像一些对象的创建基本上都是使用new来创建的。后来因为公司的项目使用到了dagger,才对Android的依赖注入框架有所接触,众所周知的是,dagger这个框架相当灵活(上手成本实在是太高),导致一些activity的注入或者context的注入都很麻烦,为了提高工作的效率,重新选择一个注入框架就显得很有必要了。

在Android中,dagger、koin和hilt是三个比较出名的注入框架,dagger已经排除在外了,那么也就剩下koin和hilt,这两者之间之所以还是选择了hilt,毕竟它是jetpack库里的,算是google的亲儿子了,使用难易度上多少会比koin好很多吧(当然这是我的猜测,毕竟koin我也没使用过),总的来说,就hilt和dagger相比,hilt真香...

好了,废话不多说。在hilt的使用中,官网上(这里吐槽一下官网上的教程,每个字我都认识,但是组合起来就很难看懂...英文好的同学直接看英文吧,中文太难理解了)基本上都是告诉我们如何在单模块中使用,但在实际开发的时候,多模块往往才是我们的选择(别问,问就是灵活哈哈...),本文就主要介绍一下怎么在多模块中集成hilt

首先先简单介绍一下项目的组织结构,如图所示:

项目结构图

 其中,config.gradle中声明了我们所需要的依赖,这里贴一份config.gradle的伪代码,大伙可以自行的去修改

ext {
    isDebug = false
    android = [
            compileSdk : 31,
            minSdk     : 21,
            targetSdk  : 31,
            versionCode: 2,
            versionName: "1.0"
    ]

    libVersion = [
            hilt    : '2.38.1',
            database: '2.4.2',
            hutool  : '5.7.21',
            okhttp  : '4.9.3',
            arouter : '1.5.2'
    ]
    libs = [
            publicLibs : [
                    'androidx.core:core-ktx:1.6.0',
                    'androidx.appcompat:appcompat:1.3.0',
                    'com.google.android.material:material:1.3.0',
                    'androidx.constraintlayout:constraintlayout:2.0.4',
            ],
            localLibs  : [
                    //本地的基础库
                    ':moduleBase:common',
                    ':moduleBase:basic',
                    ':moduleBase:database',
                    ':screenMatch',
            ],
            core       : [
                    //逻辑代码库
                    ':moduleCore:login',
                    ':moduleCore:start',
                    ':moduleCore:main'
            ],
            otherLibs  : [
                    //其他一些三方的库
                   
            ],
            jsonLib    : [
                    core    : [
                            "com.squareup.moshi:moshi-kotlin:1.13.0",
                            "com.squareup.moshi:moshi:1.13.0",
                            "com.squareup.retrofit2:converter-moshi:2.9.0"
                    ],
                    compiler: "com.squareup.moshi:moshi-kotlin-codegen:1.13.0"

            ],
            routerLib  : [
                    core    : "com.alibaba:arouter-api:${libVersion.arouter}",
                    compiler: "com.alibaba:arouter-compiler:${libVersion.arouter}"

            ],

            //****************重点:这里声明了hilt
            injectLib  : [
                    core    : [
                            "com.google.dagger:hilt-android:${libVersion.hilt}",
                    ],
                    compiler: "com.google.dagger:hilt-android-        compiler:${libVersion.hilt}",

            ],
            dataBaseLib: [
                    core    : [
                            "androidx.room:room-runtime:${libVersion.database}",
                            "androidx.room:room-ktx:${libVersion.database}",
                            "androidx.room:room-rxjava2:${libVersion.database}",
                            "androidx.room:room-paging:${libVersion.database}"
                    ],
                    compiler: "androidx.room:room-compiler:${libVersion.database}"
            ],
            "RoomigrantLib":[
                    core:'com.github.MatrixDev.Roomigrant:RoomigrantLib:0.3.4',
                    compiler:'com.github.MatrixDev.Roomigrant:RoomigrantCompiler:0.3.4'
            ]
    ]

}

那么怎么使用这个文件呢?打开项目级的build.gradle,添加如下代码

apply from:"config.gradle"

如图所示:

 OK,到此我们就将config.gradle这个文件引入到了工程中,还需要在模块的build.gradle中调用一下,这里我们以common这个模块举例。

首先我们在common模块的build.gradle文件的头部定义一个变量,

def cfg = rootProject.ext

如图所示:

 再在该文件中的denpendencies中引用

解释一下,这里我们对hilt的依赖使用implementation,这里必须每个模块都对hilt依赖,而不能采用common依赖hilt,其他模块依赖common的方式间接的依赖hilt,否则同步gradle的时候会报如下错,如图:

不要忘了头部的hilt插件的引用:

plugins {
    id 'xxx'
    id 'xxx'
    id 'xxx'
    ...
    id 'dagger.hilt.android.plugin'
}

 OK,到这里我们便能在项目中使用Hilt了,接下来便是如何使用hilt了。官网上首先提到的是我们需要一个@HiltAndroidApp去标注一个Application类

在项目中我们一般会使用一个类去继承Application并扩展它,这里我们叫它BaseApplication, 那么问题来了,这个BaseApplication到底应该放在哪里呢?是放在某个模块下面?还是放在app壳上?答案是放在App壳上,否则就会报错,如图:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.vegle.RobotConfigurator, PID: 6061
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.vegle.RobotConfigurator/com.vegle.start.ui.activity.StartActivity}: java.lang.ClassCastException: com.vegle.common.DaggerBaseApplication_HiltComponents_SingletonC$ActivityCImpl cannot be cast to com.vegle.start.ui.activity.StartActivity_GeneratedInjector
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: java.lang.ClassCastException: com.vegle.common.DaggerBaseApplication_HiltComponents_SingletonC$ActivityCImpl cannot be cast to com.vegle.start.ui.activity.StartActivity_GeneratedInjector
        at com.vegle.start.ui.activity.Hilt_StartActivity.inject(Hilt_StartActivity.java:63)
        at com.vegle.start.ui.activity.Hilt_StartActivity$1.onContextAvailable(Hilt_StartActivity.java:34)
        at androidx.activity.contextaware.ContextAwareHelper.dispatchOnContextAvailable(ContextAwareHelper.java:99)
        at androidx.activity.ComponentActivity.onCreate(ComponentActivity.java:322)
        at androidx.fragment.app.FragmentActivity.onCreate(FragmentActivity.java:249)
        at com.vegle.basic.base.BaseActivity.onCreate(BaseActivity.kt:33)
        at android.app.Activity.performCreate(Activity.java:8000)
        at android.app.Activity.performCreate(Activity.java:7984)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 

 这一点没有特别好的办法,如果有知道怎么解决这个问题的同学麻烦告知一下,至于如何避免在app壳上写过多的初始化之类的代码,倒是有很多解决方法,例如app壳中以来common模块,并使用回调的方式,将代码在common模块中实现即可,当然也有使用反射的方式实例化common中的实现类,这样就省去了依赖这个步骤,各有所长,都可以

这里我贴一下我的app壳中的BaseApplication:

@HiltAndroidApp
open class BaseApplication :Application(){
    companion object{
        const val TAG="BaseApplication"
        var IS_DEBUG = BuildConfig.DEBUG
    }
    //实例化一个接口的实现,并在各个周期中调用这个实现的方法
    private val applicationLifecycleListener = ApplicationLifecycleListenerImpl

    override fun attachBaseContext(base: Context?) {
        super.attachBaseContext(base)

//        multiDexEnabled true
        applicationLifecycleListener.attachBaseContext(base, IS_DEBUG)
    }
    override fun onCreate() {
        super.onCreate()

        applicationLifecycleListener.onCreate(this)

        Log.e(TAG,"BaseApplication--->")

    }

    /**
     * This method is for use in emulated process environments.  It will
     * never be called on a production Android device, where processes are
     * removed by simply killing them; no user code (including this callback)
     * is executed when doing so.
     */
    override fun onTerminate() {
        super.onTerminate()
        applicationLifecycleListener.onTerminate()
    }
}

到这里对hilt的初始化就完成了,不要忘了在AndroidManifest.xml中对BaseApplication的引用

 OK,开始使用hilt,我们在common模块下建个包,包名随便,自己知道就好,但最好是顾名思义,我这里就叫它di,并在di目录下建立一个AppModule类:

内容的话就看图吧,就是按照官网的使用手册食用即可:

在其他模块下也是一样的,只要把@HiltAndroidApp初始化的位置弄好其他模块下只需要弄个Module出来就可以了,这也是hilt方便的地方,hilt帮我们创建并管理component,免去了我们手动去创建和维护component,我们就只需要关注Module里有啥就行了,而不用关心他们如何创建 。

OK!搞定收工!第一次写博客,可能有些地方组织的不是特别好,多多指教,不喜勿喷~

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值