【发布时间】:2019-05-22 08:15:25
【问题描述】:
我写了一个基本的bound service based on the Android documentation,但 LeakCanary 告诉我服务正在泄漏。
- 是有泄漏还是我错误配置了 LeakCanary?
- 如何编写不泄漏的绑定服务?
代码
class LocalService : Service() {
private val binder = LocalBinder()
private val generator = Random()
val randomNumber: Int
get() = generator.nextInt(100)
inner class LocalBinder : Binder() {
fun getService(): LocalService = this@LocalService
}
override fun onBind(intent: Intent): IBinder {
return binder
}
override fun onDestroy() {
super.onDestroy()
LeakSentry.refWatcher.watch(this) // Only modification is to add LeakCanary
}
}
如果我从以下活动绑定到服务,LeakCanary 会检测到服务已泄漏
class MainActivity: Activity() {
private var service: LocalService? = null
private val serviceConnection = object: ServiceConnection {
override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
service = (binder as LocalBinder).getService()
}
override fun onServiceDisconnected(name: ComponentName?) {
service = null
}
}
override fun onStart() {
super.onStart()
bindService(Intent(this, LocalService::class.java), serviceConnection, BIND_AUTO_CREATE)
}
override fun onStop() {
super.onStop()
service?.let {
unbindService(serviceConnection)
service = null
}
}
}
┬
├─ com.example.serviceleak.LocalService$LocalBinder
│ Leaking: NO (it's a GC root)
│ ↓ LocalService$LocalBinder.this$0
│ ~~~~~~
╰→ com.example.serviceleak.LocalService
Leaking: YES (RefWatcher was watching this)
【问题讨论】:
-
Context 类中没有任何标志 BIND_AUTO_START...为什么要分别在 onCreate - onDestroy 方法中绑定 - 取消绑定服务?
-
你是对的,这是一个错字。标志应该是
BIND_AUTO_CREATE。在 onCreate 和 onDestroy 中服务是否绑定和未绑定无关;无论您使用哪种生命周期方法来绑定和取消绑定,它都会泄漏。但我会更改我的示例以匹配 Android 文档。 -
你能不能尝试...将 Binder 类移动到它自己的独立类而不是内部类,并将随机数生成器移动到该类。然后在服务内部,将它实例化为一个字段,并在 onBind() 中返回它。我在想也许 LeakCanary 认为这是一个泄漏,因为活页夹内部类持有对外部类(服务)的引用,并且对活页夹的引用被另一个具有它自己的生命周期(活动)的组件持有。
-
内部类是问题所在:stackoverflow.com/a/49365796/5823014
-
@JánosSicz-Mesziár 我同意,但是一旦服务被销毁,就不应该持有对活页夹的引用
标签: android android-service android-service-binding leakcanary