Android之Dagger&Hilt依赖注入使用指南

这篇具有很好参考价值的文章主要介绍了Android之Dagger&Hilt依赖注入使用指南。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

Dagger2 是一个 Dependency Injection(DI) 依赖注入框架。它提供给 JavaAndroid 使用,主要用于模块间解耦、提高代码的健壮性和可维护性

使用了 IOC (控制反转)的思想,在编译阶段使用 APT 利用 Java 注解生成 Java 代码,然后结合部分手写代码来完整依赖注入工作。

运行前需要先编译一次项目,目的是用 APT 生成中间代码。Dagger2 不使用反射,在编译阶段生成代码,所以不会程序性能有影响。

Dagger2 官网

Dagger2 Github


IOC

解释:

IOC 全名为 Inversion of Control ,概念大体是借助于“第三方”实现具有依赖关系的对象之间的解耦。

IOC和DI的区别:

Martin Fowler探讨既然 IOC 是控制反转,到底哪些方面的控制被反转了?其实是获得依赖对象的过程被反转了,控制反转后,获得依赖对象的过程从自身管理变成了 IOC 容器主动注入,后来给控制反转取了更适合的名字“依赖注入”。实际上给出了实现 IOC 的方法:依赖注入

Android之Dagger&Hilt依赖注入使用指南,# 依赖注入,android,kotlin,android-studio


Dagger2的注解

@Inject

@Inject 这个注解本身并没有作用,它需要依赖于注入框架才具有意义,可以用来标记构造函数、属性和方法

1.1 标记构造函数
  • 被标记的构造函数可以有 0个或多个依赖作为参数
  • 同一个类中最多只可以标记一个构造函数
class People @Inject constructor(val name:String = "Tom")

注意在 Kotlin 中这种写法是不被允许的,因为这等价于 Java 中的多个构造方法 People(String name), People(),正确的写法应该是这样:

data class People constructor(val name: String) {
    @Inject
    constructor() : this("Tom")
}
1.2 标记属性
  • 被标记的属性不能是 final 的,Kotlin中不能是 val
  • 被注入进的属性不能用 private 修饰(是 Dagger2 不支持,而非 @Inject 不支持)
@Inject
lateinit var people:People
1.3 标记方法
  • 被标记的方法可以有 0个或多个依赖作为参数
  • 方法不能是抽象的。
class HomeActivity : AppCompatActivity() {
    private lateinit var people:People

    @Inject
    fun setPeople(people:People){
        this.people = people
    }
}

这种方法注入和属性注入并没有什么本质上的不同,实现效果也基本一样。还有一种做法是 @Inject 标记被注入类的某个方法,该方法会在类的构造方法之后接着被调用:

data class People constructor(val name: String) {
    @Inject
    constructor() : this("Tom")

    init {
        println("init:$name")
    }

    @Inject
    fun hello(){
        println("hello:$name")
    }
}

class HomeActivity : AppCompatActivity() {
    @Inject
    lateinit var people:People

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_home)

        //执行相关注入操作
        ...
        println(people.toString())
    }
}

运行结果是这样的:

01-02 11:57:30.995 16601-16601/? I/System.out:  init:Tom
01-02 11:57:30.995 16601-16601/? I/System.out:  hello:Tom
01-02 11:57:30.995 16601-16601/? I/System.out:  People(name=Tom)

@Component

可以理解为一个注射器,可以算是 Dagger2 中最核心的一个注解,用来标记一个接口或者抽象类。使用 @Component 标记的接口,会在编译时自动生成一个 Dagger+类名的实现类实现依赖注入。在 Component 中一般可以定义两种方法:

@Module

用来标记类,为 Component 提供依赖,相当于告诉 Component,如果需要依赖可以来找我,当然前提是在 Component 中配置了该Module。同时 Module 可以通过 includes 依赖其他的 Module。

@Provides

用来标记 Module中的方法,该方法的返回类型是你需要提供的依赖类型。
举个自己项目中的例子,我需要在presenter中创建一个pl2303对象,pl2303对象的创建又需要context和pl2303Interface,所以我们需要提供三个依赖,因为context在其他地方也要用,我们单独提出来:

@Singleton

默认情况下,@Inject 获取到的依赖对象是非单例的,要想实现单例,需要用 @Singleton 对Module中的provide方法和Conponent接口进行标注。


Dagger&Hilt的使用

模拟场景:假设 App 需要使用 Retrofit 进行网络访问

1.1 添加依赖

build.gradle(:app) 里添加以下依赖库

plugins {
    ...
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'
}

dependencies {
		...
  
    // ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1"

    //Dagger - Hilt
    implementation "com.google.dagger:hilt-android:2.38.1"
    implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03"
    implementation "androidx.hilt:hilt-navigation-compose:1.0.0"
    kapt "com.google.dagger:hilt-android-compiler:2.37"
    kapt "androidx.hilt:hilt-compiler:1.0.0"

    // Retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.3'
}

build.gradle(Dagger&Hilt) 里添加以下代码

buildscript {
    ....
  
    dependencies {
        classpath "com.google.dagger:hilt-android-gradle-plugin:2.38.1"
    }
}

1.2 添加一个应用程序类

/**
 *  这是一个应用程序类,用于传递上下文
 *  需要在注册清单中声明这个文件
 */
@HiltAndroidApp
class MyApp :Application()
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:name=".MyApp"
        ...
				>
        ...
    </application>

</manifest>

1.3 给 MainActivity 添加入口注解

@AndroidEntryPoint// 入口点注释
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            DaggerHiltTheme {
                val viewModel = hiltViewModel<MyViewModel>()
            }
        }
    }
}

1.4 创建网络访问接口

interface MyApi {
		
  	//模拟网络请求
    @GET("test")
    suspend fun doNetworkCall()

}

1.5 创建存储库接口

interface MyRepository {
  
    suspend fun doNetworkCall()
  
}

1.6 创建存储库实现类

/**
 *  问题:
 *  1、如何把 MyApi 放入我们的存储库中,因为存储库中需要 MyApi 这个依赖
 *  2、如何让 Dagger-Hilt 知道我们想在这里使用 MyApi
 *
 *  解决方案:
 *  1、直接在构造器里添加我们的 MyApi
 *  2、通过创建依赖注入的容器(Module)来帮助,使用@Inject注解通过构造器注入
 */

class MyRepositoryImpl @Inject constructor(
    private val api: MyApi,
    private val appContext: Application
) : MyRepository {

    init {
        val appName = appContext.getString(R.string.app_name)
        println("Hello from the MyRepositoryImpl. The app name's $appName")
    }

    override suspend fun doNetworkCall() {
				//模拟网络请求
    }
}

1.7 创建全局单例模块

@Module
@InstallIn(SingletonComponent::class)// 安装到单例组件
object AppModule {

    /**
     *  每当我们提出请求时,例如在存储库中尝试注入 MyApi 实例,
     *  然后 DaggerHilt 会在其 Module 中查找是否能找到对应的实例,
     *  如果找到,它将获取实例并传递给存储库。
     */
    @Provides//告知这里提供了一个依赖
    @Singleton//单例范围注释
    fun provideMyApi(): MyApi {
        return Retrofit.Builder()
            .baseUrl("https://test.com")
            .build()
            .create(MyApi::class.java)
    }


    @Provides
    @Singleton
    fun provideMyRepository(
        api: MyApi,
        app: Application,
        @Named("hello1") hello: String
    ): MyRepository {
        return MyRepositoryImpl(api, app)
    }


    /**
     * 常见问题:
     * 如果我们所需要的依赖项的类型一样,
     * DaggerHilt 如何知道传递哪个参数给我们?
     *
     * 解决方案:
     * 使用 @Named("") 注解标记,在传参时也对应加上这个注解即可
     */
    @Provides
    @Singleton
    @Named("hello1")
    fun provideString1() = "Hello 1"

    @Provides
    @Singleton
    @Named("hello2")
    fun provideString2() = "Hello 2"
}

1.8 单独创建接口和抽象类的模块

最佳实践:如果想注入接口或者抽象类,有更简单的方法实现,在 di 包新建一个模块

@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {

    // 因为这里时提供依赖项的不同方式,所以这里不称为提供,叫<绑定>
    @Binds
    @Singleton
    abstract fun bindMyRepository(
        myRepository: MyRepositoryImpl
    ): MyRepository
}

1.9 常见问题

2.1 相同类型的依赖项无法识别

当我们需要注入依赖时,在生产实例的模块中查找到多个类型相同的实例时,又或者我们的依赖项的类型一样时 DaggerHilt 如何知道传递哪个参数给我们。解决方案:使用 @Named("") 注解,代码如下:

//使用 @Named("") 注解标记,在传参时也对应加上这个注解即可
@Provides
@Singleton
fun provideMyRepository(
    api: MyApi,
    app: Application,
    @Named("hello1") hello: String
): MyRepository {
    return MyRepositoryImpl(api, app,hello)
}


@Provides
@Singleton
@Named("hello1")
fun provideString1() = "Hello 1"

@Provides
@Singleton
@Named("hello2")
fun provideString2() = "Hello 2"
2.2 如何注入依赖项到 Service

想把依赖项注入到后台运行的 Service 中,如果给 Service 创建构造器注入是不起作用的,因为不能给 Service 构造器,所以用(字段注入)注意字段注入不能是 Private,解决方案:使用字段注入代码如下:

@AndroidEntryPoint
class MyService :Service(){

    @Inject
    lateinit var repository: MyRepository

    override fun onCreate() {
        super.onCreate()
        // 在 onCreate 执行完后,可以直接调用 repository 进行网络访问不需要自己进行初始化
        //repository.doNetworkCall()
    }

    override fun onBind(p0: Intent?): IBinder? {
        return null
    }
}

rvice 构造器,所以用(字段注入)注意字段注入不能是 Private,解决方案:使用字段注入代码如下:文章来源地址https://www.toymoban.com/news/detail-725947.html

@AndroidEntryPoint
class MyService :Service(){

    @Inject
    lateinit var repository: MyRepository

    override fun onCreate() {
        super.onCreate()
        // 在 onCreate 执行完后,可以直接调用 repository 进行网络访问不需要自己进行初始化
        //repository.doNetworkCall()
    }

    override fun onBind(p0: Intent?): IBinder? {
        return null
    }
}

到了这里,关于Android之Dagger&Hilt依赖注入使用指南的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【SQL注入】Sqlmap使用指南(手把手保姆版)持续更新

    官网下载地址:https://github.com/sqlmapproject/sqlmap sqlmap 是一款开源的渗透测试工具,可以自动化进行SQL注入的检测、利用,并能接管数据库服务器。它具有功能强大的检测引擎,为渗透测试人员提供了许多专业的功能并且可以进行组合,其中包括数据库指纹识别、数据读取和访问

    2024年04月10日
    浏览(27)
  • 【通义千问】大模型Qwen GitHub开源工程学习笔记(1)-- 使用指南、依赖库和软件

    9月25日,阿里云开源通义千问140亿参数模型Qwen-14B及其对话模型Qwen-14B-Chat,免费可商用。 立马就到了GitHub去fork。 GitHub: GitHub - QwenLM/Qwen: The official repo of Qwen (通义千问) chat pretrained large language model proposed by Alibaba Cloud. 官方的技术资料也下载了,看这里==https://qianwen-res.oss-cn-b

    2024年02月03日
    浏览(52)
  • 2. 使用IDEA创建Spring Boot Hello项目并管理依赖——Maven入门指南

    前言:本文将介绍如何使用IDEA创建一个Spring Boot Hello项目,并通过Maven来管理项目的依赖。我们从项目的创建到代码的编写,再到项目的构建和运行,一步步演示了整个过程。 🚀 作者简介:作为某云服务提供商的后端开发人员,我将在这里与大家简要分享一些实用的开发小

    2024年02月10日
    浏览(42)
  • 【2023最新版】超详细Sqlmap安装保姆级教程,SQL注入使用指南,收藏这一篇就够了

    一、sqlmap简介 sqlmap是一个自动化的SQL注入工具,其主要功能是扫描,发现并利用给定的URL进行SQL注入。目前支持的数据库有MySql、Oracle、Access、PostageSQL、SQL Server、IBM DB2、SQLite、Firebird、Sybase和SAP MaxDB等 Sqlmap采用了以下5种独特的SQL注入技术 基于布尔类型的盲注,即可以根据

    2024年02月10日
    浏览(50)
  • android speechRecognizer原生语音识别使用指南

    背景:语音拍照功能的实现 不让用三方算法库 所以只能选择android 原生speechRecognizer 其实就是解决语音转文字  文字转好了逻辑就很好处理 speechRecognizer的用法 SpeechRecognizer 位于 android.speech package 中 源码:/frameworks/base/core/java/android/speech/SpeechRecognizer.java 即 谷歌Android SpeechRe

    2024年02月08日
    浏览(37)
  • Android widget 小部件使用指南强化版

    小部件是主屏幕定制的一个重要方面。您可以将它们视为应用程序最重要的数据和功能的“概览”视图,这些数据和功能可以直接在用户的主屏幕上访问。用户可以在主屏幕面板上移动小部件,如果支持的话,还可以调整它们的大小以根据自己的喜好定制小部件中的信息量。

    2024年01月19日
    浏览(35)
  • Android SeekBar使用避坑指南

    SeekBar是Android原生UI组件,可以用来调节进度,广泛应用于音乐、视频进度展示调控、音量、亮度调节等功能里。 SeekBar的使用很简单,这里就不再介绍了,本文着重介绍一下作者最近在使用SeekBar遇到的几个坑,希望大家以后可以避免。 如图,如何去实现这样一个可拖动进度

    2024年02月07日
    浏览(44)
  • Android 图片加载库之Coil详解与使用指南

    了解Coil Android图片加载库的优势、集成方法和使用方式。掌握Coil的特点,如性能优化、轻量级、易用性强,以及高级功能如GIF动态加载、图片变换等。

    2024年02月08日
    浏览(44)
  • grasscutter 使用指南——Android/Windows/IOS端均已支持

    grasscutter是某二次元手游的开源后端,目前功能并不完整,但正在contributers正在全速开发中,未来可期。可以部署在linux和windows下,通过代理与各种平台的客户端进行交互。本文提供grasscutter的linux端部署(windows端比较简单)、windows/andriod/ios端的客户端连接指导,其中安卓提

    2023年04月09日
    浏览(29)
  • Android-Library-开源库-JCenter-&-JitPack-安装使用指南

    [注册地址](https://bintray.com/signup/oss ) 1.尽量不要在官网注册,因为官网注册的是企业版,我们需要的是个人版 2.直接关联 Github账号进行注册 登录(建议) PS:如果Github账户使用了qq邮箱,163邮箱等可能会无法注册,可以尝试给Github账户 增加一个邮箱例如 Gmail 步骤2:在Bintra

    2024年04月17日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包