When should I use `context!!` versus `context?` in...
# android
c
When should I use
context!!
versus
context?
in my Fragments? I'm thinking using
context!!
in my lifecycle methods and
context?.let{}
where I get callbacks
g
Depends on your use case
Also I use
requireContext()
to get non-nullable context
c
Can you elaborate a bit?
For non-UI logic i already use an application context provided by DI, so I don't really have issues on that layer
g
sure, but if you want Activity context on Fragment you have 2 choices: use getContext() for nullable context or requireContext() to crash if context is null
d
isn't
!!
make the app crash when there is some error? i think its not wise for app that alr launch
g
But sometimes you want to crash if somebody call method in a wrong way, wrong lifecycle phase and so on
as I said, it depends on case
if it’s just some non-important operation, you can use
?
and just do nothing if contetxt is null, sometimes you need context
c
I'd recommend to never use double-bang
r
depends on the case tbh, sometimes it can make sense to just use
!!
instead of adding convoluted checks imho, as long as the stacktrace in case of a crash is clear enough (especially when working on legacy code)
c
Luckily until today I was always able to get rid of it
I'd like to see it as "hey, this is me probably shooting myself and yes, I'm completely fine with it."
g
!!
instead of adding convoluted checks imho
I prefer methods like requireContext (in this case) or something like getOrThrow() instead of
!!
👍 1
👌 1
d
hmm interesting discussion
c
Then I guess it is a question of when can you use
requireContext()
. Is it valid to only use it in lifecycle methods (
onAttach() -> onDestroy
) ?
r
also on user action I'd say, on a click listener for example it makes sense to assume the context is not null
c
That also makes sense. Do we know when
context
starts being null? Like precisely after a lifecycle method?
r
pretty sure it's null before
onAttach
/ after
onDetach
g
also on user action I'd say, on a click listener for example it makes sense to assume the context is not null
Actually this is not always true, click is also asyncronous action managed by looper's event loop and in some cases you can get call backs after fragment detach
👍 2
i
c
Related to that, should references to views be nullable or non nullable in fragments? The article said you could use
val recyclerView: RecyclerView by bindView(R.id.recycler)
which ended up being non nullable. Is that safe?
I use databinding and
binding?. let {}
a lot in callbacks. Is there a way to check if we can do operations on our views?
i
I am not familiar with data binding, so my answer may not be complete, but regarding views it depends. In above example where you retrieve view by Id - I would keep them non-nullable as usually when the view is there you messed something up and we want to follow fail-fast practice. However there may be a scenario where on activity have more than one layout for different device configuration (eg. phone vs tablet or vertical vs horizontal). There layout may differs in child views (eg. Tablet cna display more data, so there may be some extra view). If you are aware of this fact then you can make a view nullable, because it exists only in some of the layouts. Regarding Presenters from MVP nullable/non-nullable type of the view it’s an architectural decision, but just to be safe I would keep them nullable. Regarding context usually we can use application context for things like
startActivity
. You can easily obtain it from custom application class (configured in AndroidManifest) and assume it will be initialises latter and always be non-nullable (utilising
lateinit
modifier)
Copy code
class MyApplication : Application() {
    lateinit var context: Context
    
    override fun onCreate() {
        super.onCreate()

        this.context = context
    }
}
Then you can just staticky access it (not so nice) or inject it into Activity (proper way of doing things)
t
in some device/situation Application.onCreate is not called before initializing of Activity/Service/Receiver. you may know it when reading crash report in real world. the work around is call something static method in companon object in each onCreate on Activity/Service/Receiver/etc.
r
val recyclerView: RecyclerView by bindView(R.id.recycler)
is not safe, it you try to access it before onViewCreated for example (or after view destroyed) it will throw an NPE, so technically using
RecyclerView
instead of
RecyclerView?
can be considered wrong. But it all depends on where you decide to draw the line for "too many checks", and what you want to do when one of these fail (in some cases you can just ignore what happened if the view is gone, but in others you could want to consider it an error)
using the application context is often wrong though 🤔
c
why is using the application context often wrong?
As long as you don't pass that to views, I thought that's fine
g
Application context is fine, but you cannot use to start a new activity on the same task, show dialog and for some other things
r
there's a reason you get a local and app context, they're not the same thing, resources you get from them can be different for example, especially in multi-window / split view, themes are also different, basically anything UI related should always use local context, or you can be in for some nightmarish debugging
also I've seen it used with things like Glide for loading images, that's also pretty awful and can easily lead to leaks, since it won't link loading to the right context. Glide links loading to the context lifecycle to cancel calls/reuse bitmaps, most of the time it will still be freed using app context, but not in all cases (again, nightmarish debugging, but even a step above previous one)