When to Call Activity Context or Application Context

When to call activity context OR application context?

getApplicationContext() is almost always wrong. Ms. Hackborn (among others) have been very explicit that you only use getApplicationContext() when you know why you are using getApplicationContext() and only when you need to use getApplicationContext().

To be blunt, "some programmers" use getApplicationContext() (or getBaseContext(), to a lesser extent) because their Java experience is limited. They implement an inner class (e.g., an OnClickListener for a Button in an Activity) and need a Context. Rather than using MyActivity.this to get at the outer class' this, they use getApplicationContext() or getBaseContext() to get a Context object.

You only use getApplicationContext() when you know you need a Context for something that may live longer than any other likely Context you have at your disposal. Scenarios include:

  • Use getApplicationContext() if you need something tied to a Context that itself will have global scope. I use getApplicationContext(), for example, in WakefulIntentService, for the static WakeLock to be used for the service. Since that WakeLock is static, and I need a Context to get at PowerManager to create it, it is safest to use getApplicationContext().

  • Use getApplicationContext() when you bind to a Service from an Activity, if you wish to pass the ServiceConnection (i.e., the handle to the binding) between Activity instances via onRetainNonConfigurationInstance(). Android internally tracks bindings via these ServiceConnections and holds references to the Contexts that create the bindings. If you bind from the Activity, then the new Activity instance will have a reference to the ServiceConnection which has an implicit reference to the old Activity, and the old Activity cannot be garbage collected.

Some developers use custom subclasses of Application for their own global data, which they retrieve via getApplicationContext(). That's certainly possible. I prefer static data members, if for no other reason than you can only have one custom Application object. I built one app using a custom Application object and found it to be painful. Ms. Hackborn also agrees with this position.

Here are reasons why not to use getApplicationContext() wherever you go:

  • It's not a complete Context, supporting everything that Activity does. Various things you will try to do with this Context will fail, mostly related to the GUI.

  • It can create memory leaks, if the Context from getApplicationContext() holds onto something created by your calls on it that you don't clean up. With an Activity, if it holds onto something, once the Activity gets garbage collected, everything else flushes out too. The Application object remains for the lifetime of your process.

Difference between Activity Context and Application Context

They are both instances of Context, but the application instance is tied to the lifecycle of the application, while the Activity instance is tied to the lifecycle of an Activity. Thus, they have access to different information about the application environment.

If you read the docs at getApplicationContext it notes that you should only use this if you need a context whose lifecycle is separate from the current context. This doesn't apply in either of your examples.

The Activity context presumably has some information about the current activity that is necessary to complete those calls. If you show the exact error message, might be able to point to what exactly it needs.

But in general, use the activity context unless you have a good reason not to.

What is different between MainActivity.this vs getApplicationContext()

Which context to use?

There are two types of Context:

Application context is associated with the application and will always be the same throughout the life of application; it does not change. So if you are using Toast, you can use application context or even activity context (both) because Toast can be displayed from anywhere within your application and is not attached to a specific window. But there are many exceptions. One such exception is when you need to use or pass the activity context.

Activity context is associated with the activity and can be destroyed if the activity is destroyed; there may be multiple activities (more than likely) with a single application. Sometimes you absolutely need the activity context handle. For example, should you launch a new Activity, you need to use activity context in its Intent so that the newly-launched activity is connected to the current activity in terms of activity stack. However, you may also use application's context to launch a new activity, but then you need to set flag Intent.FLAG_ACTIVITY_NEW_TASK in intent to treat it as a new task.

Let's consider some cases:

MainActivity.this refers to the MainActivity context which extends Activity class but the base class (Activity) also extends Context class, so it can be used to offer activity context.

getBaseContext() offers activity context.

getApplication() offers application context.

getApplicationContext() also offers application context.

For more information please check this link.

Deciding between Activity Context or Application Context to Instantiate SQLiteOpenHelper

I Think by now I do have a better understanding of the concept of Context. I would like to share a link I found that clarifies this topic. http://t.co/9R0bPWiKc5

Pass Application Context to the view instead of Activity Context

getApplicationContext() should be used with the view, which will be having scope outside the Activity (An example of it might be when you bind to a Service from an Activity).

But for Defining Views like as you mentioned above (to define a Button), you should Definitely use Activity's Context (MyActivity.this or Simply this).

The reason for it is if you use getApplicationContext(), it will live as longer as the Whole Application lives. But for a Button, it should destroy as soon the Activity finishes, So it is always better to use this(Activity's Context), when defining such type of Views.

if I use Application Context instead of Activity Context there is no
Exception

There is no exception because both are valid Contexts. Its upon you that if you keep your view alive for entire application lifetime, even if it is not needed (which would ultimately lead to Memory Leakages), or you want to destroy it with as soon as the Activity finishes.

Call Application context in Activity

Activity is something we do declare in the manifest and then start them using intent, However, the creation of an instance of an activity is done by the system and not by us. An instance is created using constructor, but if it is us then we can have any number of overloaded constructors. But the system needs only one constructor which should be a zero parameter constructor and it should be public.

So your activity signature

class PhotoActivity(application: Application) : AppCompatActivity() {

should be changed to

class PhotoActivity() : AppCompatActivity() {

To call the fun getDatabase(context: Context): PictureDatabase you can pass this from the activity. Activity is an indirect child of Context.

You can do it in the following ways,

  1. private val pictureDao by lazy{ PictureDatabase.getDatabase(this) }
  2. private lateinit var pictureDao:PictureDatabase
    then in onCreate() initialize it
final override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.your_layout)
PictureDatabase.getDatabase(this)
//your logic goes here
}

How do I call the context correctly to start an Activity

Not sure if I can answer all your questions but here's my two cents:

Your code looked like this when your app crashed:

btn_scan.setOnClickListener {
val mIntent = Intent(applicationContext, Scanner::class.java)
mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
mIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
applicationContext.startActivity(mIntent)
}

The error message said you should use FLAG_ACTIVITY_NEW_TASK when starting an Activity from outside of an Activity context. You used the Application context which is like a "cousin" of the Activity context inheritance-wise (see ContextWrapper for subclasses and their relations), so the Intent flags were checked and the required flag was missing.

But why can the flag be missing if you set it explicitly?

mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK

That's because you assign another value to mIntent.flags immediately after this:

mIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP

If you want to have both flags you have to add them:

mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + Intent.FLAG_ACTIVITY_CLEAR_TOP

Now the app no longer crashes.

But is the Application context even necessary here? Your code is part of an Activity after all, and Activity is an indirect subclass of Context.

You possibly tried the following and it worked:

btn_scan.setOnClickListener {// Note: your IDE tells you "it: View!"
val mIntent = Intent(applicationContext, Scanner::class.java)
mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
mIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
this.startActivity(mIntent)
}

Because inside the OnClickListener lambda, the View is referred to by "it", there is no ambiguity: "this" refers to the Activity, no crash.
(Of course now you could skip the Intent.FLAG_ACTIVITY_NEW_TASK)

Things look differently when you have something like this:

  with(btn_scan){ // this: Button!
setOnClickListener{ // it: View!
val mIntent = Intent(applicationContext, Scanner::class.java)
mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + Intent.FLAG_ACTIVITY_CLEAR_TOP
this.startActivity(mIntent)
}
}

Now your IDE won't accept this.startActivity(mIntent). This is because here "this" refers to the Button. If you want another, "outer this", you have to say explicitly which one. In Kotlin, you do so by adding @ActivityName.

I suppose the same goes for coroutine code inside an Activity (although I must confess I'm not yet a coroutine expert): whenever the Activity "this" is hidden behind some local "this", you need the annotation.

Back to familiar ground: the context property of a Fragment is the Activity's context if the Fragment is attached to an Activity, else it is null. So if it's not null you can use it for starting an Activity.

But you can even use the Button's context property, since it is identical to the Activity context as well:

with(btn_scan){ // this: Button!
setOnClickListener{
val mIntent = Intent(applicationContext, Scanner::class.java)
mIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
this.context.startActivity(mIntent)
}
}


Related Topics



Leave a reply



Submit