If you have ever developed applications for Android, you have probably come across the term Context โ€”one of the most fundamental, but at the same time mysterious concepts in this ecosystem. It appears in almost every class: from simple Toastnotifications to complex database operations. But what is it really? Why is it called a โ€œgod-objectโ€ Android, and why misuse Context can lead to memory leaks or even application crashes?

In this article we will look Context from scratch: from the basic definition to the intricacies of working with its different types (Application Context, Activity Context, Service Context). You'll learn how to choose the right context for a specific task, what mistakes developers most often make, and how to avoid common problems. Weโ€™ll also look at practical code examples that you can immediately apply in your projects.

Are you ready to figure it out once and for all? Then let's start with the main thing: what is Context v Android and why not a single application can do without it.

What is Context in Android: a simple explanation

Context (context) is an abstract class in Androidthat provides access to application resources, runtime information, and system interaction capabilities. Simply put, it is a โ€œbridgeโ€ between your code and the operating system Android.

Through Context you can:

  • ๐Ÿ“ Access resources (strings, images, styles) through getResources().
  • ๐Ÿ“ฑ Launch new ones Activity using startActivity().
  • ๐Ÿ“ก Send and receive Broadcastmessages.
  • ๐Ÿ—ƒ๏ธ Work with the file system and databases.
  • ๐Ÿ” Find out information about the current state of the device (orientation, screen size and etc.).

Without Context your application would not be able to interact with Androidthe system. For example, to show a simple Toastto the user, you need context:

Toast.makeText(context, "Hello, world!", Toast.LENGTH_SHORT).show();

But why not just pass the context wherever you need it? The fact is that Incorrect use of Context can lead to memory leaks is one of the most common problems in Androiddevelopment. We'll talk about this later, but for now let's take a look at what types of context there are.

๐Ÿ“Š How often do you encounter memory leaks in Android?
Constantly
Sometimes
Rarely
Never checked

Context types in Android: Application vs Activity vs Service

In Android there are several types of context, and each of them has its own purpose. The main ones are:

Context type Where to get Lifetime When to use
Application Context getApplicationContext()
MyApp.getContext() (via Singleton)
As long as the application lives For operations not tied to the UI (loading images, working with databases, Singleton classes)
Activity Context this (inside Activity)
MyActivity.this
While visible Activity on the screen For working with the UI (dialogs, Toast, launching new Activity)
Service Context this (inside Service) While running Service For operations in the background (downloading files, playing music)
BroadcastReceiver Context Transferred to onReceive() Only while running onReceive() For short-term operations (showing a notification, launching Service)

Critical error: using Activity Context in Singleton classes (for example, for loading images) leads to memory leaks, since Singleton keeps a reference to the Activity even after it is closed.

Let's take a closer look at each type:

1. Application Context

This is a context that exists on throughout the entire life cycle of the application. It can be obtained through getApplicationContext() or create a Singletonclass for easy access:

public class MyApp extends Application {

private static Context context;

@Override

public void onCreate() {

super.onCreate();

context = getApplicationContext();

}

public static Context getContext() {

return context;

}

}

โœ… When to use:

  • ๐Ÿ”„ For operations that do not depend on the UI (loading data, working with the database).
  • ๐ŸŒ In Singleton-classes (for example, for working with a network).
  • ๐Ÿ“ฆ When creating objects that should live longer than one Activity.

โŒ When NOT to use:

  • ๐Ÿšซ To display dialogs or Toast (may crash if the UI thread is inactive).
  • ๐Ÿšซ For operations that require the current UI state (such as screen orientation).
๐Ÿ’ก

If you need to show the Toast from the background, use Application Context, but wrap the call in runOnUiThread() or Handler with Looper.getMainLooper().

2. Activity Context

This is a context tied to a specific Activity. It lives while Activity is visible on the screen, and is destroyed along with it. It turns out simply through this inside the class. data-i="108">When to use: Activity.

โœ… When to use:

  • ๐ŸŽจ For operations with UI: show dialogs Toast, launch new ones Activity.
  • ๐Ÿ”— For binding Views (for example, in LayoutInflater).
  • ๐Ÿ“ฑ To access the current state Activity (orientation, screen sizes).

โŒ When NOT to use:

  • ๐Ÿšซ In Singleton-classes or static fields (will lead to memory leak).
  • ๐Ÿšซ For long operations (for example, downloading a large file), since Activity may close before the operation is completed.
Why is Activity Context dangerous in AsyncTask?

If you pass Activity Context to AsyncTask, and the user closes the Activity before the task is completed, then the context will remain โ€œhangingโ€ in memory. This leads to leaks and possible crashes when trying to update the UI of a non-existent Activity.

3. Service Context

The context Service is similar to Activity Context, but it is tied to the background service. It lives while it is running Serviceand is destroyed along with it. It is used for operations that must be performed in the background (for example, playing music or downloading files).

โš ๏ธ Attention: Do not confuse Service Context with Application Context. The first one is tied to a specific one Service and will die with it, and the second one lives while the application is running.

How to correctly pass Context: best practices

One of the most common mistakes of novice developers is passing Activity Context where it is not needed. This leads to memory leaks when an object holds a reference to Activitythat is already there. closed. Here's how to avoid such problems:

1. Use WeakReference for Activity Context

If you need to pass Activity Context to a class that can survive Activity (for example, AsyncTask or Callback), wrap it in WeakReference:

public class MyAsyncTask extends AsyncTask {

private WeakReference contextRef;

public MyAsyncTask(Context context) {

this.contextRef = new WeakReference<>(context);

}

@Override

protected Void doInBackground(Void... voids) {

Context context = contextRef.get();

if (context != null) {

// Working with context

}

return null;

}

}

2. Prefer Application Context for long operations

If your task is not related to the UI (for example, loading data from the network or working with a database), always use Application Context. It is not tied to the lifecycle Activity and will not cause leaks:

// Correct:

MyDatabaseHelper dbHelper = new MyDatabaseHelper(getApplicationContext());

// Incorrect (may lead to leaks):

MyDatabaseHelper dbHelper = new MyDatabaseHelper(this); // this = Activity Context

3. Context

Never store Context in static fields! This is a guaranteed way to get a memory leak:

// BAD:

public class MyUtils {

private static Context sContext; // Memory leak!

public static void init(Context context) {

sContext = context; // Store the link forever

}

}

Use instead Application Context or pass the context through method parameters.

Is the Application Context used for long-running operations?|Are there static links to the Activity Context?|Are weak links wrapped? (WeakReference) where needed?|Isnโ€™t Activity Context passed to Singleton classes?-->

Typical mistakes when working with Context and how to avoid them

Even experienced developers sometimes make mistakes when working with ContextHere are the most common ones and how to make them. fixes:

1. Memory leak through inner classes

Anonymous inner classes (for example, Listeners or Callbacks) automatically hold a reference to the outer class. If this class is Activity, then you get. leak:

// BAD: Activity leak

button.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// This code holds a reference to the Activity!

}

});

โœ… Solution: Use static inner classes or null references in onDestroy().

2. Showing dialogs after closing the Activity

If you show a dialog in the background (for example, after loading data), and the user manages to close Activity, the application will crash with an error WindowManager$BadTokenException.

// BAD: may crash if the Activity is closed

new AlertDialog.Builder(this)

.setTitle("Error")

.show();

โœ… Solution: Check whether Activityis closed before showing the dialog:

if (!isFinishing()) {

new AlertDialog.Builder(this)

.setTitle("Error")

.show();

}

3. Using Context in threads

Context is tied to the UI thread, and using it from a background thread may crash. For example, an attempt to show Toast from Background Thread will cause CalledFromWrongThreadException.

โœ… Solution: Perform all operations with the UI in the main thread:

runOnUiThread(new Runnable() {

@Override

public void run() {

Toast.makeText(MyActivity.this, "Message", Toast.LENGTH_SHORT).show();

}

});

๐Ÿ’ก

Always check that the Activity (isFinishing()) is not closed before showing dialogs or Toasts from background tasks.

Practical examples: where and which Context to use

Let's look at real-life scenarios and Let's determine which Context is suitable for each of them.

1. Loading an image into ImageView

If you are using a library like Glide or Picasso to load images, always pass Activity Context for ImageView and Application Context for cache:

// Correct:

Glide.with(this) // Activity Context for ImageView

.load("https://example.com/image.jpg")

.into(imageView);

// Or for Application Context (if the ImageView is not bound to an Activity):

Glide.with(getApplicationContext())

.load("https://example.com/image.jpg")

.into(imageView);

2. Creating notifications

To create notifications, always use Application Context, since notifications can be shown even after closing Activity:

NotificationCompat.Builder builder = new NotificationCompat.Builder(
    getApplicationContext(), // Not Activity Context!

CHANNEL_ID

)

.setSmallIcon(R.drawable.notification_icon)

.setContentTitle("New message")

.setContentText("You have a new notification!");

3. Working with SharedPreferences

Any context is suitable for working with SharedPreferences any context, but it is better to use Application Contextto avoid leaks:

// Good:

SharedPreferences prefs = getApplicationContext()

.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);

// Bad (if this = Activity Context in Singleton):

SharedPreferences prefs = this.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);

4. Launching a new Activity

To launch a new Activity always use Activity Context:

Intent intent = new Intent(this, SecondActivity.class);

startActivity(intent);

โš ๏ธ Attention: Do not use Application Context to launch Activity - this will cause AndroidUtil.AndroidRuntimeException.

5. Working with BroadcastReceiver

Internally BroadcastReceiver the context is passed to the method onReceive() and lives only during its execution. Do not store this context longer than necessary!

public class MyReceiver extends BroadcastReceiver {

@Override

public void onReceive(Context context, Intent intent) {

// Use context only here!

Toast.makeText(context, "Message received!", Toast.LENGTH_SHORT).show();

// DO NOT save context to static fields!

}

}

Memory leaks due to misuse Context are one of the most insidious problems in Android. They do not always lead to an immediate crash, but gradually eat up memory, slow down the application and can cause OutOfMemoryError. Here's how to find and fix them:

1. Tools for finding leaks

Use these tools to find leaks:

  • ๐Ÿ” Android Profiler (built into Android Studio) - shows memory usage in real time.
  • ๐Ÿ› ๏ธ LeakCanary - library that automatically detects memory leaks and shows them in notifications.
  • ๐Ÿ“Š Memory Analyzer (MAT) โ€”a tool for deep analysis of memory dumps.

Connection example LeakCanary:

// In build.gradle (Module: app):

dependencies {

debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10'

}

2. Typical signs of leaks Context

If you observe these symptoms, most likely there is a leak in your code Context:

  • ๐Ÿ“ˆ Application memory grows even after everyone is closed Activity.
  • ๐Ÿข The application begins to slow down after prolonged use.
  • ๐Ÿ’ฅ Crash with an error OutOfMemoryError.
  • ๐Ÿ”„ When rotating the screen, memory is not freed.

3. How to fix a leak: step-by-step guide

Let's say LeakCanary showed a leak in your code. Here's how to fix it:

  1. Look in the logs to see which object holds the link to Activity (for example, MyAsyncTask).
  2. Check whether Activity Context is passed there directly.
  3. Replace Activity Context on Application Context or wrap in WeakReference.
  4. Make sure that all Listeners and Callbacks are written in onDestroy().

Example of fixing a leak in AsyncTask:

// WAS (leak):

private class MyTask extends AsyncTask {

private Context context; // Holds Activity Context

public MyTask(Context context) {

this.context = context; // Leak!

}

// ...

}

// BECAME (without leak):

private static class MyTask extends AsyncTask {

private WeakReference contextRef;

public MyTask(Context context) {

this.contextRef = new WeakReference<>(context);

}

@Override

protected Void doInBackground(Void... voids) {

Context context = contextRef.get();

if (context != null) {

// Working with context

}

return null;

}

}

๐Ÿ’ก

LeakCanary is your best friend in finding memory leaks. Connect it at the development stage and test all scenarios (including screen rotation!).

FAQ: Frequently asked questions about Context in Android

โ“ Can I use Application Context to show Toast?

Technically it is possible, but it is unsafe. Application Context is not tied to the UI thread, and if you try to show Toast from the background, the application will crash. It is better to use Activity Context or wrap the call in runOnUiThread().

โ“ Why you canโ€™t store an Activity. Context in Singleton?

Because Singleton live the entire time the application is running, and Activity Context must die along with ActivityIf Singleton holds a link to Activity, it will not be collected by the garbage collector, which will lead to a memory leak.

โ“ How to get Context in a class that is not an Activity or Service?

There are several ways:

  1. Pass Context via constructor (better Application Context).
  2. Use Singleton with Application Context (as shown in the example with MyApp above).
  3. If the class is used only in Activityyou can transmit Activity Context, but watch out for leaks.
โ“ What happens if you use Wrong Context (for example, Application instead of Activity to launch an Activity)?

If you try to run Activity via Application Context, you receive AndroidUtil.AndroidRuntimeException with a message "Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag". For this to work, you need to add a flag Intent.FLAG_ACTIVITY_NEW_TASK, but this is not recommended - it is better to always use Activity Context to launch new Activity.

โ“ How to check if an Activity is not closed before showing dialog?

Before showing the dialog or Toast always check:

if (!isFinishing() && !isDestroyed()) {

new AlertDialog.Builder(this)

.setMessage("Message")

.show();

}

This will prevent a crash if Activity already closed.

Now you know about Context everything you need to avoid memory leaks and write reliable code. Remember: choosing the right context is the key to the stable operation of your application! Android everything you need to avoid memory leaks and write reliable code. Remember: choosing the right context is the key to stable operation of your application!