Many Android beginners use Context blindly, and this often leads to confusion or even memory leaks later. Understanding Context helps you write safer, cleaner code. In this article, I am trying to explain and figure out myself what context really is. I do not want to start with the definition for a context. I want to find the definition based on the how we use context in the app development.
We have Classes for each Application components and class for Application in the Android. If you try to find a parent class of these classes, deep down you will get to the ContextWrapper class. This class implements the abstract class called Context. Basically this abstract class which has methods and states and it gives access to different things.
Let’s take a look in to the places where we are using context. These are most common and frequently used places but we often won’t notice how Context plays a role in it.
1. Launching Application components
To launch application components such as Activity, Service, Broadcast receiver, Content provider we are using context. Let’s say we are launching a new activity from HomeActivity, First we create an intent and then call startActivity method. what is startActivity method where it is created? When you go to the source class you can see startActivity is in the context class. Same with startService, sendBroadcast, registerReceiver, getContentResolver.
class MainActivity : AppCompatActivity() {
/**
* 1. startActivity,
* 2. startService,
* 3. sendBroadcast,
* 4. registerReceiver,
* 5. getContentResolver
* all these methods provided by the Context class
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// To start activity
val homeActivityIntent = Intent(this, HomeActivity::class.java)
startActivity(homeActivityIntent)
// To start Service
val musicService = Intent(this, MusicService::class.java)
startService(musicService)
// To send Broadcast
val intent = Intent("com.example.snippets.ACTION_UPDATE_DATA").apply {
putExtra("com.example.snippets.DATA", "data")
setPackage("com.example.snippets")
}
sendBroadcast(intent)
// To register broadcast receiver
val broadCast = BroadCast()
val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")
ContextCompat.registerReceiver(this, broadCast, filter, ContextCompat.RECEIVER_EXPORTED)
// To talk to content provider
val cursor = contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
null, null, null, null
)
}
}
2. Context gives Application wide access
Handling Resources
In android resources such as Strings, drawables, dimensions, layouts everything is stored in the res folder. They belong to the whole application, not just a single component. Context helps to access these resources.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// To access string and drawables
val appName = resources.getString(R.string.app_name)
val icon = getDrawable(R.drawable.ic_launcher_background)
// To create a views
val button = Button(this)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
// To get layout inflator
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_view, parent, false)
return MyViewHolder(view)
}
Context not only gives access to resources but also ensures the correct variant is chosen based on configuration. In android, resources can (strings, drawables, layouts) have multiple variants.
- Locale = values-en/strings.xml vs values-ta/strings.xml
- Screen density = drawable-hdpi/ vs drawable-xxhdpi/
- Orientation = layout-land vs layout
When we use context.getResources().getString(R.string.app_name), Context understands the current configurations and provides correct resource variant.
Internally context holds the configurations class which has access to current locale, orientations, theme, screen size, density so when you call getResources context uses this configuration class and resolve which resource file to use.
Shared Preference
Shared preference one of the common way to store primitive data in android development. Shared preference is not tied to single application component it is also a part of the application. To access shared preference we rely on context.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// To access shared preference
val preferences = getSharedPreferences("FileName", Context.MODE_PRIVATE)
// getSharedPreferences is a method provided by the Context class.
}
Access and store private files
Android system provides all the Apps to store files in a specific space in the internal storage. To access and store files in that space, we depend on Context.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// To access file form internal storage
val file = File(filesDir, "filename")
val cacheFile = File(cacheDir, "filename")
// To store file in the internal storage
openFileOutput("fileName", MODE_PRIVATE).use {
it.write("Hello world".toByteArray())
}
// To list available files
val files: Array<String> = fileList()
// To create directory
getDir("dirName", Context.MODE_PRIVATE)
// To create cache file
File.createTempFile("filename", null, cacheDir)
// To delete private file
deleteFile("fileName")
}
Database
To create and access database in android, we extend this class called SQLiteOpenHelper. SQLiteOpenHelper needs Context because the database is stored in your app’s private directory. Context provides that path. Without Context, the system wouldn’t know where in your app’s sandbox to place the database.
class MyDbHelper(context: Context) : SQLiteOpenHelper(context, "mydb", null, 1) {} { … }
3. Access to system services
To access various services that not tied to application but with the system we are relied on context. Context has a method called getSystemService(serviceName). This method returns the system level service handle for a specific service. We use this to get access to different services. I have mentioned some of the services here.
- Location Manager
- Clipboard Manager
- Power Manager
- Storage Manager
- Notification Manager
// To get notification handle
val notificationManager: NotificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
In conclusion, Context is a gateway between the Application and the Android system which helps to perform various operations such as managing app components, using system services, handling resources, inflating views. Based on where we are in the application and our needs, we need to be careful about which Context we use. In the next article, I’ll dive into the different types of Context (Application, Activity, etc.) and when to use each safely.
Top comments (0)