依赖注入

Dagger2/Hilt/Koin


Dagger是由square公司开发
https://github.com/square/dagger

Dagger2是dagger的升级版,现在由Google接手维护,
https://github.com/google/dagger

Hilt是在Dagger基础上进行二次封装构建的,相对Dagger来说,代码量更少,使用更简单。不同的是,Dagger利用注解使用APT去生成辅助代码,而Hilt是利用注解使用APT和ASM(字节码插桩)去生成辅助代码。https://dagger.dev/hilt/

Koin是轻量级的依赖注入框架,性能不及dagger2/Hilt,但是简单
https://github.com/InsertKoinIO/koin

好处:

举个具体的例子,一个容器里面装的是苹果,不用Dagger2的情况下我们应该这么写:

1
2
3
4
public class Container{
Fruit f=new Apple(color,size);
...
}

上面例子面临着一个问题,Container依赖了Apple实现,如果某一天需要修改Apple为Banana,那么你一定得改Container的代码。有没有一种方法可以不改Container呢?
可以使用Dagger2,我们可以把代码改成

1
2
3
4
5
public class Container{
@Inject
Fruit f;
...
}

这样,Container的成员变量就自动初始化成Apple实例了,Container不用关心具体用哪个Fruit的实现,也不用关心到底用什么颜色多大的苹果。假如某一天要把苹果替换成香蕉,Container的代码是完全不需要改动的。


Dagger2简单使用

前提:注入方有构造函数可以@inject

@Inject:
a.在A类中标记B类字段,告诉dagger要把B类实例注入到A类中
b.在B类中标记构造方法,告诉dagger这是一个可以被注入的类,需要创建实例时,用标记的构造方法

@Component:
作为依赖方A和注入方B之间的桥梁。在Component中持有依赖方A的实例,当在A类中发现有被@Inject,会去查找B的构造方法,来创建B实例。

不需要构造函数

@Module和@Provides

implementation ‘com.google.dagger:dagger:2.35.1’
annotationProcessor ‘com.google.dagger:dagger-compiler:2.35.1’
implementation ‘com.google.dagger:dagger-android:2.35.1’
implementation ‘com.google.dagger:dagger-android-support:2.35.1’
annotationProcessor ‘com.google.dagger:dagger-android-processor:2.35.1’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class User {
private String name = "stew NB";
public String getName(){
return name;
}
}

@Module
public class UserModule {
@Provides
public User provideUser(){
return new User();
}
}

@Component(modules = UserModule.class)
public interface UserComponent {
void inject(TestDagger2Activity activity);
}

//make project

public class TestDagger2Activity extends AppCompatActivity {

@Inject
User user;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dagger);
DaggerUserComponent.create().inject(this);
Log.d("TestDagger2Activity", "onCreate: " + user.getName());
}
}

Hilt简单使用

@HiltAndroidApp:所有使用hilt的应用都需要使用这个注解,被使用在Application类上
@AndroidEntryPoint:Hilt可以为带有 @AndroidEntryPoint 注释的其他 Android 类提供依赖项,@AndroidEntryPoint:可以被用在四大组件以及View上面
@Inject:获取依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@HiltAndroidApp
public class MyApplication extends Application {

public class HttpTool {
}

@InstallIn(ApplicationComponent.class)
@Module
public class HttpModule {
@Singleton
@Provides
public HttpTool getHttp(){
return new HttpTool();
}
}

@AndroidEntryPoint
public class TestHiltActivity extends AppCompatActivity {

@Inject
HttpTool httpTool1;

@Inject
HttpTool httpTool2;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hilt);
Log.d("TestHiltActivity", "onCreate: "+httpTool1);
Log.d("TestHiltActivity", "onCreate: "+httpTool2);
}
}

Koin简单使用

ext.koin_version = ‘2.2.0-rc-3’

// Koin for Kotlin
implementation “org.koin:koin-core:$koin_version”
implementation “org.koin:koin-core-ext:$koin_version”

// Koin for AndroidX
implementation “org.koin:koin-androidx-scope:$koin_version”
implementation “org.koin:koin-androidx-viewmodel:$koin_version”
implementation “org.koin:koin-androidx-fragment:$koin_version”
implementation “org.koin:koin-androidx-ext:$koin_version”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class MyApp:Application() {

private val modules = mutableListOf(homeModule)

override fun onCreate() {
super.onCreate()
ToastUtil.init(this)
initKoin()
}

private fun initKoin() {
startKoin {
androidLogger()
androidContext(this@MyApp)
modules(modules)
}
}
}


//HomeModule.kt
val homeModule = module {
single { RetrofitManager.getService(HomeApi::class.java) }
single { HomeRepo(get()) }
viewModel { HomeViewModel(get()) }
}


class HomeFragment : BaseVMFragment<FragmentHomeBinding>() {

private val homeViewModel: HomeViewModel by viewModel()
…….

}


class HomeViewModel(private val homeRepo: HomeRepo) : BaseViewModel() {
……
}


class HomeRepo(private val homeApi: HomeApi) : BaseRepository() {
……
}