经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » Kotlin » 查看文章
kotlin使用属性委托实现依赖注入
来源:cnblogs  作者:轩恺  时间:2021/12/15 9:04:15  对本文有异议

起因

在学习安卓网络通信时翻阅了一下《第三行代码》,决定试着用一下Retrofit,实现了HttpServiceUserService

object HttpService {
    private const val BASE_URL = "http://10.0.2.2/"

    private val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    fun <T> create(serviceClass: Class<T>): T = retrofit.create(serviceClass)

    inline fun <reified T> create(): T = create(T::class.java)
}
interface UserService {

    @GET("user")
    fun getUser(
        @Query("userId") userId: Long,
    ) : Call<User>

}

在使用UserService时就只需要这样调用

HttpService.create<UserService>().getUser().await().let { 
        //do something
}

虽然已经很简便了,但实际使用的时候需要每次都通过HttpService这个单例类来构造Service,感觉还是有一点麻烦。

灵感

我想到了前段时间看到的一个开源项目ViewBindingKTX,它可以在使用视图绑定时方便很多,这是它样例代码中给出的例子

class MainActivity : AppCompatActivity() {
  private val binding: ActivityMainBinding by binding()

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding.tvHelloWorld.text = "Hello Android!"
  }
}

可以看到他使用了by关键词,也就是kotlin的语言特性属性委托。再看看binding()的具体实现

inline fun <reified VB : ViewBinding> ComponentActivity.binding() = lazy {
  inflateBinding<VB>(layoutInflater).also {
    setContentView(it.root)
    if (this is ViewDataBinding) lifecycleOwner = this@binding
  }
}

在具体实现时使用了延迟属性来实现在调用时才实例化对象。这样一来在我们使用Activity对应的binding时就会通过得到ActivityMainBinding对象实例,像极了依赖注入。

尝试

仔细一想,我们也可以为Service实现通过属性委托得到实例,来实现依赖注入的功能。先照着binding()来实现一个inject()

inline fun <reified T: BaseHttpService> inject() = lazy {
    HttpService.create<T>()
}

再在Activity中使用inject()

class MainActivity : BaseActivity<ActivityMainBinding>() {
    private val userService: UserService by inject()
    
    //other code
}

这样一来我们就不需要在Activity中显式地访问HttpService,通过inject()就可以在运行时第一次访问userService时得到对应实例。运行项目,运行成功。

总结

不得不感叹kotlin的强大之处,可以如此轻松地实现依赖注入。并且因为kotlin在实现动态代理时会转为静态代理调用而不是使用反射调用,效率会优于使用java实现。理论上这个用法不止可以在安卓中使用,在其他kotlin项目中也可以轻松实现,在降低耦合的同时简化代码,提高可读性。

原文链接:http://www.cnblogs.com/xuankaicat/p/15657484.html

 友情链接:直通硅谷  点职佳