Just out of curiosity. I have been watching a prac...
# android
m
Just out of curiosity. I have been watching a practice that is becoming popular about using backing properties to shortcut Kotlin nullability check. (For example)
Copy code
private var _binding: ViewBinding? = null
private val binding get() = _binding!!
And I was wondering why this is better than just a
lateinit property
(which, in my humble opinion, is more concise)
Copy code
private lateinit var binding: ViewBinding
Or even if
_binding
is going to be mutated to null, it would be better to use the language constructors to check the possibility. Am I missing something?
a
I guess here it is not the setup (there lateinit would also work) but the tear-down. In one of the life-cycle callbacks (e.g. onDestroy) you’d be setting the backing field to
null
to avoid leaks.
1
o
lateinit
, aka the Kotlin NPE 🙃
r
we.ll the first question is are there seniors were binding can be null
j
I think this is a very bad practice and a horrible example to put out there by Google
This should be a nullable var (because of fragment destroy view)
3
Or there are some nice delegation examples that are even view life cycle friendly
Also, the practice of writing viewModels like this:
Copy code
val _liveData = MutableLiveData()
val liveData: LiveData
    get() = _liveData
Is bad in my opinion. It is ugly and prefixing a variable to show its visibility is (again in my opinion) inconsistent and useless, it shows people don't get the concept of interfaces, which is a way more elegant way of hiding the implementation of a certain object.
j
IMO viewbinding and !! is the exact case where !! is a good practice, and it is that you should use !! when you are sure that you are going to access to a nullable variable in a specific moment when it is not null at 100%
m
If you are 100% sure that is not going to be null, then a
lateinit
fits way better, and it's more idiomatic than a backing property. My problem with this practice is that you are opening the door in your code for using
!!
in more places when you are "sure that the value is never going to be null", and that breaks the NPE safety.
About reset the state to null in the tear-down to avoid memory leaks. I have been investigating, and I was not able to find concrete examples, however, I would like to learn more about this possibility. IMO the view should not be doing anything after the onDestroy; the variable correctly scoped should not be referenced outside. When I see those cases in that you need to reset the state to null, I think often are encapsulation problems, and then you need to do the job of the GC
j
No, lateinit implies you can change the value, I prefer !! instead of having the possibility of having it mutable. At the end you can do this with delegation, so it will be under the hood, you only have to do: private val binding by viewbinding(SomeFragmentBinding::bind) changing that to var is just not a good idea.
j
@Javier what does !! Have to do with mutability? @max.cruz you should look up fragment and fragment view life cycle, if you understand what that means in practice then you understand why you should clear things in ondestroyview
j
The exposed variable should be not null and immutable. lateinit var can only help to the implementation, and it have to be null too to avoid memory leaks
m
@Joost Klitsie I understand the fragment view life cycle 😅 , for that reason I think you should not need to touch the binding after the onDestroy, then the GC should be enough to avoid any kind of memory leak, for that reason I'm asking for a concrete example to validate that theory with my profiler
j
It is not enough, I have fixed leaks with this
BTW @jw can help here, I think he is the author of viewbinding
j
@max.cruz ok do this: 1. Have a fragment somewhere 2. Replace that fragment and put it to backstack 3. Pop the fragment from backstack You should observe: 1. Your fragment and your fragment view gets created 2. Your fragments view gets destroyed, your fragment itself is still alive (here you might profile the view is still in memory because of your binding) 3. Your fragments view gets recreated. If here you still reference old view bindings, you will have an illegalstateexception upon interaction
m
@Javier but then something is holding the reference to the binging I guess.
@Joost Klitsie onDestroy is not called when your fragment goes and come back from the backstack, after onDestroy only onDetach should happen I guess (

https://i.stack.imgur.com/G57CI.png

)
j
Yes but onDestroyView is called and that is the whole point we have been discussing :)
👍 1
So it is best practice to remove any view references (like viewbinding) in ondestroyview because of possible view recreation
Activities don't have this problem as their view lifecycle is similar to the activity lifecycle
But for fragments somebody got very creative :)
m
Thanks @Joost Klitsie I see more clearly the point now, so the idea is to clear the reference onDestroyView and then re-create the binding again with onCreateView to avoid retaining the reference when the view is in the back stack
However, still, I wouldn't say I like the backing property mechanism to handle that 😅
j
Check the delegation post
👍 1
☝️ 1
1
m
Thanks for sharing @Javier I will take a look
👍 1
🙂 1