What is Context?
What is Context?
Context is an interface that provides access to application-specific resources and classes, as well as calls for application-level operations. Think of it as a handle to the environment your code runs in.
Every Android component is a Context:
- Activity is a Context (and a Window)
- Service is a Context (but no UI)
- Application is a Context (app-wide)
- ContentProvider is NOT a Context directly (use
contextproperty)
What Context Provides
// Accessing resources
val appName = context.getString(R.string.app_name)
val color = ContextCompat.getColor(context, R.color.primary)
val drawable = ContextCompat.getDrawable(context, R.drawable.ic_launcher)
// System services
val inflater = context.getSystemService(LayoutInflater::class.java)
val connectivity = context.getSystemService(ConnectivityManager::class.java)
val alarmManager = context.getSystemService(AlarmManager::class.java)
// Starting activities
context.startActivity(Intent(context, DetailActivity::class.java))
// File and database access
val file = File(context.filesDir, "data.json")
val db = Room.databaseBuilder(context, AppDatabase::class.java, "app.db").build()
// Package information
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
val appName = context.applicationInfo.loadLabel(context.packageManager)
Activity Context vs Application Context
Activity Context is tied to the activity lifecycle. It knows about the window, theme, and UI state. Use it for operations that need to interact with UI.
Application Context lives as long as the app process. It has no window or theme awareness. Use it for operations that don't need UI.
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Activity context — has window, theme
val dialog = AlertDialog.Builder(this) // this = Activity Context
.setTitle("Alert")
.setMessage("Hello")
.create()
// Application context — no window, no theme
val appContext = applicationContext
// appContext cannot show dialogs (no window)
}
}
When to Use Application Context
Application context is safer for long-lived operations because it doesn't depend on activity lifecycle:
// Correct — Application context for singletons
object DatabaseProvider {
private var instance: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
return instance ?: synchronized(this) {
// Use applicationContext to avoid leaking Activity
val builder = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"app.db"
)
instance = builder.build()
instance!!
}
}
}
// WRONG — Using Activity context in a singleton
object BadDatabaseProvider {
private var instance: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
return instance ?: synchronized(this) {
// This leaks the Activity!
val builder = Room.databaseBuilder(
context, // Activity context!
AppDatabase::class.java,
"app.db"
)
instance = builder.build()
instance!!
}
}
}
Context and Memory Leaks
Context and Memory Leaks
The most common Android memory leak is holding a reference to an Activity context after the activity is destroyed. This prevents garbage collection of the entire activity and all its views.
Common Leak Patterns
1. Static reference to Activity context:
// WRONG
object LeakyManager {
var context: Context? = null
fun init(context: Context) {
this.context = context // If activity context, it leaks
}
}
// CORRECT
object SafeManager {
var context: Context? = null
fun init(context: Context) {
this.context = context.applicationContext // Safe
}
}
2. Inner class holding implicit reference to Activity:
// WRONG — Kotlin lambdas in coroutines
lifecycleScope.launch {
delay(10000)
// Activity might be destroyed after 10 seconds
Toast.makeText(this@MainActivity, "Done", Toast.LENGTH_SHORT).show()
}
// CORRECT — Use viewLifecycleOwner scope
viewLifecycleOwner.lifecycleScope.launch {
delay(10000)
// If view is destroyed, coroutine is cancelled
Toast.makeText(requireContext(), "Done", Toast.LENGTH_SHORT).show()
}
3. Handler with delayed messages:
// WRONG
val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
// Activity context leaked if message is pending when activity is destroyed
}
}
handler.sendMessageDelayed(msg, 60000)
// CORRECT — Clear handler in onDestroy
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacksAndMessages(null)
}
4. Registering listeners without unregistering:
// WRONG
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
EventBus.getDefault().register(this) // Never unregistered
}
// CORRECT
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
}
Detecting Memory Leaks
- LeakCanary: Automatic leak detection in debug builds. Add
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.12")to your dependencies. - Android Studio Profiler: Memory tab shows object count and heap dumps.
- StrictMode: Detects leaked closeable objects and sqlite cursor leaks.
Rules to Prevent Context Leaks
- Never store Activity context in a static variable or singleton
- Use
applicationContextfor long-lived operations - Use
viewLifecycleOwner.lifecycleScopefor coroutines in fragments - Unregister listeners and callbacks in
onStop/onDestroy - Use WeakReference if you must hold a reference that shouldn't prevent GC
Context Best Practices
Context Best Practices
Choosing the Right Context
| Use Case | Context | Why |
|---|---|---|
| Inflate layout | Activity | Needs theme for style resolution |
| Show dialog/alert | Activity | Needs window token |
| Start Activity | Activity or Application | Application works but activity gives better transition |
| Access resources | Any | Application is fine |
| Database | Application | Long-lived, no UI needed |
| Singleton/Service | Application | Prevents activity leak |
| Glide/Picasso | Activity (or Application) | Image libraries handle lifecycle |
ContextWrapper Pattern
You can wrap a context to modify behavior without subclassing:
// Custom context wrapper for theming
val themedContext = object : ContextWrapper(baseContext) {
override fun getResources(): Resources {
// Modify resources behavior
return super.getResources()
}
}
Context in View Constructors
When creating custom views, use TypedArray from the context to read XML attributes:
class CustomView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
init {
val typedArray = context.obtainStyledAttributes(
attrs, R.styleable.CustomView, defStyleAttr, 0
)
val color = typedArray.getColor(R.styleable.CustomView_customColor, Color.BLACK)
val size = typedArray.getDimension(R.styleable.CustomView_customSize, 0f)
typedArray.recycle()
}
}
Testability and Context
Avoid passing Activity context directly to ViewModels or repositories. Use dependency injection to provide what's needed:
// Instead of passing context everywhere
class UserRepository(private val context: Context) { ... }
// Inject only what you need
class UserRepository(private val userDao: UserDao) { ... }
This makes testing easier — you can mock the DAO without needing a real context.
Quiz
1. What is the primary difference between Activity context and Application context?
2. Why does storing Activity context in a singleton cause a memory leak?
3. When should you use applicationContext?
4. How does LeakCanary help with Context leaks?
Flashcards
Question
What is Android Context?
Click to reveal answer
Answer
An interface providing access to application resources, system services, and operations. Activities, Services, and Application are all Contexts.
Question
When should you use applicationContext over Activity context?
Click to reveal answer
Answer
For singletons, database initialization, and any long-lived operation. Never use Activity context in objects that outlive the activity.
Question
What is the most common cause of Context memory leaks?
Click to reveal answer
Answer
Holding a reference to an Activity after it's destroyed — e.g., static variables, singletons, unregistered callbacks.
Question
Can you show a dialog with Application context?
Click to reveal answer
Answer
No. Dialogs require a window token, which only Activity context provides. Application context has no window.
Revision Notes
Key Takeaways
- 1. Context is your app's handle to the environment — resources, services, and system operations
- 2. Activity context has UI awareness; Application context does not
- 3. The #1 memory leak is holding Activity context after the activity is destroyed
- 4. Use applicationContext for singletons and long-lived operations
- 5. LeakCanary automatically detects Activity context leaks in debug builds
Interview Tips
- • Explain what Context provides and why it exists
- • Know when to use Activity vs Application context for each scenario
- • Be ready to draw a memory leak diagram with Activity and singleton
- • Discuss how to test code that depends on Context using dependency injection
Cheat Sheet
Context Cheat Sheet
What Context Provides:
- Resources (strings, drawables, colors)
- System services (LayoutInflater, ConnectivityManager)
- File and database access
- Starting activities and services
- Package information
Activity vs Application Context:
- Activity: has window, theme, UI state
- Application: no window, app-wide, long-lived
Memory Leak Rules:
- Never store Activity context in static/singleton
- Use applicationContext for long-lived operations
- Unregister callbacks in onStop/onDestroy
- Use viewLifecycleOwner.lifecycleScope for coroutines
- Use LeakCanary to detect leaks
When to Use What:
- Dialog/Toast → Activity
- Database/Singleton → Application
- Inflate layout → Activity
- Start Activity → Either (prefer Activity)