Android hilt 依赖注入使用详解

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/128424833
本文出自【赵彦军的博客】

官方文档

https://developer.android.com/training/dependency-injection/hilt-android#groovy

demo 如下:

https://gitee.com/zhaoyanjun/hilt

作用域于树图

在这里插入图片描述
组件生命周期
在这里插入图片描述

添加依赖

在根目录 build.gradle 的添加 hilt 插件

plugins {
    
    
  ...
  id 'com.google.dagger.hilt.android' version '2.44' apply false
}

完整如下:

plugins {
    
    
    id 'com.android.application' version '7.3.1' apply false
    id 'com.android.library' version '7.3.1' apply false
    id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
     
    //添加hilt 依赖
    id 'com.google.dagger.hilt.android' version "2.44" apply false
}

在 app 的 build.gradle ,的 plugins 目录添加

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

android {
    
    
  ...
}

dependencies {
    
    
  implementation "com.google.dagger:hilt-android:2.44"
  kapt "com.google.dagger:hilt-compiler:2.44"
}

// Allow references to generated code
kapt {
    
    
  correctErrorTypes true
}

初始化hilt

Application 添加 @HiltAndroidApp 注解

@HiltAndroidApp
public class App extends Application {
    
    
}

MainActivity 使用

共享类 @Inject

使用 @Inject 注解作用在类的构造函数中

public class Util {
    
    

    String token = "1234444";

    @Inject
    public Util() {
    
    
    }
}

在 MainActivity 添加依赖注入 @AndroidEntryPoint

MainActivity 类中添加 @AndroidEntryPoint 注解

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    
    
}

在 android 项目中,但凡一个类要使用 hilt 依赖注入能力,就要在类头部加入 @AndroidEntryPoint 注解

使用 @Inject 申明需要使用的注入类

 @Inject
 lateinit var appToken: Util

完整的代码如下:

import android.os.Bundle
import android.util.Log
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    
    

    @Inject
    lateinit var appToken: Util

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

        findViewById<TextView>(R.id.tv).text = appToken.token
    }
}

这样例子就可以跑起来了。

但是这里有个问题,每一个申明 @Inject lateinit var appToken: Util 的对象都是一个新对象,如果我们要想在 Activity 作用域中实现对象共享,类似于 jetpack 中的 viewModel 。我么需要 @ActivityScoped 注解

@ActivityScoped 作用域

代码如下:

@ActivityScoped
public class Util {
    
    

    String token = "1234444";

    @Inject
    public Util() {
    
    
    }
}

使用 @ActivityScoped 修饰的注入类,在 Activity 类多次申明注入,得到的实例只有一个。

@Singleton 作用域

全局单例作用域

@Singleton
public class Util {
    
    

    String token = "1234444";
    Context context;

    @Inject
    public Util(@ApplicationContext Context context) {
    
    
        this.context = context;
    }

    public String getName() {
    
    
        return context.getResources().getString(R.string.app_name);
    }
}

@ViewScoped

作用域只局限于 View , 即时两个 view 有父子关系,那么注入的也是新的实例。

@ViewScoped
public class ViewUtil {
    
    
    public String token = "1234444";

    @Inject
    public ViewUtil() {
    
    

    }
}

举例说明:

 <com.zyj.hint.MyViewGroup
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <com.zyj.hint.MyView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </com.zyj.hint.MyViewGroup>

    <com.zyj.hint.MyView2
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

分别在 MyViewGroup 、MyView 、MyView2 注入实例,得到的是三个不同的实力。

viewGroup ViewScoped com.zyj.hint.util.ViewUtil@2b7364f
view1 ViewScoped com.zyj.hint.util.ViewUtil@3aae2e5
view2 ViewScoped com.zyj.hint.util.ViewUtil@5ae86b

完整代码详见:https://gitee.com/zhaoyanjun/hilt

@ViewModelScoped

定义共享类

@ViewModelScoped
public class ViewModelUtil {
    
    
    public String token = "1234444";

    @Inject
    public ViewModelUtil() {
    
    

    }
}

在 ViewModel 中申明注入类

@HiltViewModel
class MainViewModel @Inject constructor() : ViewModel() {
    
    

    @Inject
    lateinit var viewModelUtil: ViewModelUtil

    fun run() {
    
    
        Log.d("yu--", "MainViewModel $viewModelUtil")
    }
}

Activity 中获取 ViewModel 实例

import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    
    

   private lateinit var viewModel: MainViewModel

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

        viewModel = ViewModelProvider(this)[MainViewModel::class.java]
        viewModel.run()
    }
}

完整代码详见:https://gitee.com/zhaoyanjun/hilt

构造参数,添加 Context参数@ApplicationContext、@ActivityContext

如果是 Activity 实例的 context , 需要添加 @ActivityContext

public class Util {
    
    

    String token = "1234444";
    Context context;

    @Inject
    public Util(Context context) {
    
    
        this.context = context;
    }

    public String getName() {
    
    
        return context.getResources().getString(R.string.app_name);
    }
}

但是这种已编译就报错

在这里插入图片描述
解决也很好弄,在 Context 上添加 @ApplicationContext 注解,代码如下:

public class Util {
    
    

    String token = "1234444";
    Context context;

    @Inject
    public Util(@ApplicationContext Context context) {
    
    
        this.context = context;
    }

    public String getName() {
    
    
        return context.getResources().getString(R.string.app_name);
    }
}

添加 @ApplicationContext 注解后,Context 参数就会自动添加。

如果是 Activity 实例的 context , 需要添加 @ActivityContext , 代码如下:

public class Util {
    
    

    String token = "1234444";
    Context context;

    @Inject
    public Util(@ActivityContext Context context) {
    
    
        this.context = context;
    }

    public String getName() {
    
    
        return context.getResources().getString(R.string.app_name);
    }
}

猜你喜欢

转载自blog.csdn.net/zhaoyanjun6/article/details/128424833