On button click I'm starting a new activity like this:
Intent(requireContext(), SecondActivity::class.java).apply {
putExtra(RECORDED_SUCCESSFULLY, filePath)
(activity as FirstActivity).finish()
startActivity(this)
}
But because I need to finish this activity before creating a new one, requireContext() here will be occasionally equal null and this causes a crash. So my question is, can I use getApplicationContext() or should I use safe call with getContext() in this situation?
It's prefered to use Activityname.this or getApplicationContext().
Remember there are two types of contexts in android and when you are dealing with activity components such as finish use Activityname.this
Related
What is the difference between requireActivity() and requireContext() when starting a new Activity Intent
startActivity(Intent(requireContext(), A::class.java))
startActivity(Intent(requireActivity(), B::class.java))
A Fragment theoretically can be attached to a Context that is not an Activity. In this case requireActivity() would throw an Exception when requireContext() wouldn't.
You would know if you were using a Fragment in this unconventional way, so for all intents and purposes, there is no practical difference.
requireContext() is returning the same Activity instance as requireActivity() would, but it is upcast to Context. An Activity would be implicitly upcast to Context anyway when you pass it to the Intent constructor, since it is expecting a Context.
requireActivity() a method that returns the non-null activity instance to fragment or throws an exception. If you are 100% sure that in your fragment's lifecycle, activity is not null
requireContext() returns a nonnull Context , or throws an exception when one isn't available.
I have a very simple on click listener in my fragment:
button?.setOnClickListener {
val intent = Intent(MyActivity.createIntent(context!!)) // crash here because context is null
startActivity(intent)
}
Crashlytics shows that some users are getting KotlinNullPointerException crashes when clicking on this specific button. Now I know the problem is happening because I am force unwrapping the Context. If I simply wrapped it inside a nullcheck, it would not crash.
But I assume that there's a bigger underlying issue in my code because I always force unwrap context when I need it and I only have issues with this specific piece of code.
What's the rule here? Should we always nullcheck our Context or not?
If you will look at the source code of fragment.getContext() method, you will see:
#Nullable
public Context getContext() {
return mHost == null ? null : mHost.getContext();
}
Which means that getContext can return null. Internally mHost represents an Activity fragment is attached to. Fragment isn't always attached to it's hosting activity, you can observe this using onAttach / onDetach lifecycle callbacks.
In your case, as already mentioned, best approach would be to use context from a View
view.setOnClickListener { it.context }
But in general, always check nullable things, and don't do !! even if you're sure it is not null. In such way you will have less error prone code, providing an alternative way of handling nulls.
Inside button click you can easily use : view.getContext() to get the context or in Kotlin
it.context // which will be never null
i.e,
button?.setOnClickListener {
val intent = Intent(MyActivity.createIntent(it.context)) // this wont ever crash
startActivity(intent)
}
most propably you will be okay with code like that
button?.setOnClickListener {startActivity(MyActivity.createIntent(it.context))}
I believe on your MyActivity.createIntent() fun you return Intent
I know this is a basic question but i have seen that using the method getApplicationContext() to get the context work at places where the "this" keyword does't work, especially inside an onClickListener.
Why is this?
In the case of an OnClickListener, this is the anonymous class of the OnClickListener, therefore not a Context.
Whereas calling that method works because it's from the Activity class.
Alternatively, MyActivity.this works as well.
getActivity(): Used inside a Fragment to get the context of activity it is currently associated to.
this: Returns the context of current block in which it is called. If it is called inside an onClickListener then it would return the context of that listener, not the activity.
MyActivity.this: Returns the context of the activity. This can be used at the place of getActivity() as an alternate. (MyActivity should be read as the activity name you are using).
Is there anything that can only be achieved by ApplicationContext but ActivityContext or vice versa?
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.
Is there any difference between Activityname.this() & this in Android?
I am trying to open an activity from same activity with button in dialog box? I am using getApplicationContext() in intent. In some mobiles it works, but in others it force closes?
Between ActivityName.this and this which one I should use & why?
Is there any difference between Activityname.this() & this in Android ?
This depends on where you are calling it from. If you are inside the Activity, not inside of a listener or inner class like in onCreate then no. They both refer to the Activity context.
If you are say inside of an onClickListener then yes. this refers to the listener and you need to use ActivityName.this or something like
someButton.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Intent i = (v.getContext(), NextActivity.class); use the button context which will be the same as the activity context
startActivity(i);
}
});
This will be the same as when using a Dialog or AlertDialog, you will want to use ActivityName.this
This is an answer that talks about the difference of Contexts but there's a better one I will see if I can find
A great Context explanation
Edit for more completeness
AFAIK, getApplicationContext() or ActivityName.this is fine for Toasts. The example in the docs uses getApplicationContext(). But the Toast Docs says
Parameters
context The context to use. Usually your Application or Activity object.
So there may be certain instances where one is better but I have always used Activity Context and I guess I will until I am corrected on this.
no MyActivity.this is the same thing as just using this when you are in the activity itself and not something like a runnable where this would refer to the runnable and not the context
you should always use this or getActivity() if in a fragment and never use getApplicationContext()
check here for why you shouldn't use getApplicationContext()
getApplication() vs. getApplicationContext()