Kotlin中Application的实例写法

本文探讨了在Kotlin中如何在工具类中使用Application的Context,避免内存泄漏的问题。通常,静态变量持有Context会导致内存泄漏,但通过在companion object中声明并使用非静态方式可以解决这一问题。文中还提到了Java中的常见实现,并解释了为何在Kotlin中不推荐使用静态Context的原因。

引言


Context大家都不陌生,最先接触的使用应该就是startActivity。当有些代码需要复用抽离出来作为工具类方法的时候,Context从哪里来呢?(这里并不是讲Activity、Context、ApplicationContext等等这个家族之间剪不断理还乱的暧昧关系所以统称Context)
在Activity中获取Context的方法
Activity中的Context
在Fragment中获取context的方法
Fragment中的Context
Fragment中的Activity
工具类中的Context可以通过参数传递过来,这种场景适用于需要通过当前的上下文情景做某些事情,例如:特定Activity的场景切换(触发登录)、权限申请(回调监听)等。
还有一种情况就是不需要情景,单纯获取数据资源的情况,例如我碰到的:获取系统屏幕px/dp的比率(命名为dpTopx)。
此时传递Activity、Fragment的Context是完全没问题的,以前我的做法是将dpTopx写到BaseActivity和BaseFragment中。
这次我单独将它写到工具类,通过Application的Context来计算。有没有嗅到优化的气息!!
于是问题就来了,Kotlin中怎么写?

正文


熟悉java的应该都不会陌生,且大多项目应该都是这么写的(如果不是请一定要教我)。
java的Application
分析一下:
- 继承自Application
- 静态内部变量
- 赋值
- 公共方法

于是照猫画虎
kotlin的Application
由于kotlin静态的声明放在了companion object块中最初还真不舒服。

这里讲讲警告和!!
警告
1、编译器提醒不可以将Context声明为静态变量,这样会导致内存泄漏。
讲解一下:如果有A(main)、B、C三个Activity它们都有自己的静态变量Context,A启动了B,此时B.context被分配内存并赋值,B再启动C,C.context被分配内存并赋值,按返回,到了B,C应该被GC,但由于context为静态变量且对C有引用,所以C在内存中常驻,再返回,到了A,B同样应该被GC,但context为静态变量,所以B也赖在内存,因此产生了内存泄露。除非kill app,否则B、C都被引用无法释放。

2、至于!!,用的真是,虽然永远都不会NullPointerException(去这里看笔记)

Kotlin学习中触碰到的知识点
http://www.jianshu.com/p/7cb426ee324c

忍不住了!
缘,妙不可言

忘了上图了,补一个
补的

`constructor(application: Application)` 是 Kotlin 中定义 **主构造函数** 的写法,通常用于 Android 的 `ViewModel` 或自定义组件中,表示该类需要传入一个 `Application` 上下文对象作为参数。 --- ### 🔍 语法解析: ```kotlin class MyViewModel @Inject constructor(application: Application) : AndroidViewModel(application) { // ... } ``` - `class MyViewModel`:定义一个类。 - `@Inject constructor(application: Application)`:这是主构造函数,并使用了 Dagger 注解 `@Inject`,表示可以通过依赖注入框架自动注入该类的实例。 - `application: Application`:构造函数的参数,是一个 `Application` 类型的对象,用于获取应用上下文。 - `: AndroidViewModel(application)`:调用父类 `AndroidViewModel` 的构造函数,并将 `application` 传入。 --- ### ✅ 常见使用场景: #### 1. **AndroidViewModel 的子类构造** 用于需要访问 `Application` 上下文的 `ViewModel`: ```kotlin class MyViewModel(application: Application) : AndroidViewModel(application) { val context: Context = application.applicationContext } ``` #### 2. **配合 Dagger/Hilt 实现依赖注入** 在使用 Dagger 或 Hilt 的项目中,构造函数通常会加上 `@Inject` 注解: ```kotlin class MyViewModel @Inject constructor( application: Application, private val repository: MyRepository ) : AndroidViewModel(application) { // ... } ``` 这样 Dagger 会自动帮我们创建这个类的实例,并注入所需的依赖。 --- ### ✅ 为什么需要传入 `Application`? - `ViewModel` 通常需要访问上下文(如访问资源、数据库、网络等),但不能直接持有 `Activity` 或 `Context`,否则会导致内存泄漏。 - `AndroidViewModel` 提供了对 `Application` 上下文的访问,它是安全的,因为 `Application` 的生命周期与整个应用一致。 --- ### ✅ 与普通构造函数的区别: | 写法 | 是否是主构造函数 | 是否支持依赖注入 | 是否可加注解 | |------|------------------|------------------|--------------| | `class MyClass constructor(context: Context)` | ✅ 是 | ❌ 否 | ✅ 是 | | `class MyClass(context: Context)` | ✅ 是 | ❌ 否 | ✅ 是 | | `class MyClass { constructor(context: Context) }` | ❌ 否(次构造) | ✅ 是 | ✅ 是 | --- ### ✅ 示例代码: ```kotlin class UserViewModel @Inject constructor( application: Application, private val userRepository: UserRepository ) : AndroidViewModel(application) { fun loadUser(userId: String) { userRepository.loadUser(userId) } fun getAppName(): String { return getApplication<Application>().getString(R.string.app_name) } } ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值