Please tell me is it allowed to put ActivityContext/ApplicationContext in a variable as shown in the code below?
class MainActivity : Activity() {
private val context = applicationContext
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
As you know in Android, the roots of the garbage collector are: static variables and active threads.
Case 1. We put applicationContext in the context
variable.
private val context = applicationContext
Will there be memory leak? I don't think so, because applicationContext is a singleton in the process of running the application.
Case 2. We put activity or this in the context
variable.
private val context = this
Will there be memory leak? My intuition tells me not to do this. Because Activity can be destroyed (for example, when the screen is rotated). If I'm right, please explain why there will be a memory leak, because no garbage collector root is used. Maybe I'm wrong and this behavior is allowed.
P.S. Will the situation be similar if we put variable context
in companion object
?
class MainActivity : Activity() {
companion object {
private val context = applicationContext // or this
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
CodePudding user response:
Those are properties, not variables. It's important to understand the distinction, although not for this particular question.
Your very first code block is fine because the application context reference will be cleared when the Activity instance is released, and Activities have shorter lifetimes than the Application.
The code example Case 1 is perfectly fine in any situation (static reference or instance reference) for the reason you said. The Application context is a singleton that lives for the lifetime of your app so it cannot be leaked.
For case 2: if you use this
in a companion object, this
refers to the companion object, not the Activity instance. (There would be no way for the companion object to statically get an Activity instance on its own because there is no single Activity instance for it to find at any given moment.) However, if you do this, you will indeed leak the Activity instance:
class MainActivity : Activity() {
companion object {
private var context? Context? = null
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
context = this
}
}
// or:
private var context? Context? = null // top-level property
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
context = this
}
}
An Activity context should never be stored in a static property.
Anything referenced by an object
property or top-level property (outside a class) cannot be garbage collected because there is a static reference to it. Not sure what you mean by no garbage collector root being used. object
and top-level properties are static references, which you said yourself are roots for the garbage collector.