目录
0. 前言
1. 依赖与注入
2. @Inject
3. @Module & @Provides
4. @Component
5. @Qualifier
6. Provider & Lazy
7. @Scope
8. 注入到Set和Map容器
9. Bind系列注解
10. dagger中依赖关系与继承关系
11. dagger.android
目标:使用dagger注入“单例”
通过我们之前对@Provides
生成的工厂类、@Inject
注解变量或方法生成的注入器以及@Component
生成的桥接类的分析,我们发现dagger每次在注入依赖时,其实都会通过工厂类创建一个新的实例,所以在上一篇文章最后,我抛出了dagger中单例的问题,本篇也是围绕着此问题展开的
Kotlin中的单例
众所周知,在kotlin中通过object
可以非常简单的构建单例,例如:
object Singleton {
// object类不能有构造函数,其也不能被外部构造
const val NAME = "Cmd"
val AGE = 24
fun info() = "$NAME-$AGE"
}
我们看下对应的java代码长啥样:
public final class Singleton {
@NotNull
public static final String NAME = "Cmd"; // 对于有const标记的变量,可见性为public,省去了get方法调用
private static final int AGE = 24; // 没有const标记的变量,可见性为private,会生成get方法(如果是var还会有set方法)
public static final Singleton INSTANCE;
public final int getAGE() {
return AGE;
}
@NotNull
public final String info() {
return "Cmd-" + AGE;
}
private Singleton() {
// 注意构造函数的可见性为private
}
static {
Singleton var0 = new Singleton(); // 在static块中初始化单例
INSTANCE = var0;
AGE = 24;
}
}
代码不难懂,唯一要注意的是kotlin的object
是饿汉式单例,在内存占用、线程安全、序列化与反序列化等方面表现并不是很好,所以如果对单例有更高的要求,建议不要直接使用object
这个语法糖。至于其他单例实现方式不是本系列重点,就不详细说明了
需求:优化代码
我觉得学习一个框架,就应该先想清楚这个框架能用在什么地方,所以通常我都会编一些需求来模拟实际使用场景
回想我们现在的代码,Activity
不仅有逻辑控制部分(根据时间选择Computer
、使用Handler
实现定时器等)还有显示视图部分(显示Computer
信息、显示timestamp
信息等),这岂不是有违单一职责原则?所以我决定将这两部分拆分,逻辑控制部分留在Activity
中,而显示视图部分则交给新的类——Monitor
借助object的全局单例
Monitor
类仅负责显示视图,为了节省内存我们不妨借助object
封装成一个“工具类”:
object Monitor {
fun show(textView: TextView, computer: Computer) {
// 在textView中显示Computer信息
val builder = StringBuilder()
computer.execute(builder)
textView.text = builder.toString()
}
fun startRefresh(textView: TextView, timestamp: Date) {
// 在textView中添加timestamp信息
val builder = StringBuilder(textView.text)
builder.append(timestamp.toString()).append("\n")
textView.text = builder.toString()
}
fun toastInfo(context: Context) {
// 通过toast显示一些信息
val builder = StringBuilder()
builder.append("Monitor: ").append(this.hashCode())
Toast.makeText(context, builder.toString(), Toast.LENGTH_SHORT).show()
}
}
当然我们可以在Activity
中直接使用这个单例,但因为本系列主题是dagger,更应该考虑怎样用dagger来注入这个单例
通过之前几篇文章的分析我们应该清楚:dagger实际上最终调用到的是我们自己写的@Provides
注解的方法来创建新的实例的,所以我们创建MonitorModule