A few days ago, I posted this question about using synthetic properties when you include the same layout in a screen multiple times.
The answer was awesome but after I tried it more for a few days, I noticed a strange behaviour:
When going forward from the fragment (the one containing the references to the view obtained by the lazy delegate) and then coming back ( I use transaction.commit()
and manager.popBackStack()
, to do this ), the labels will be empty. I already checked with the debugger if anything is null there, and nothing is.
The only solution that seems to work is replacing the by lazy
with lateinit var
and assigning them in onViewCreated
.
Do you know why? Is the solution I used still "good" as a kotlin idiom?
I include the two pieces of code for the sake of completeness:
Partially working one:
private val foundTitle by lazy { detailContainer1.title }
private val foundDescription by lazy { detailContainer1.description }
private val wantedTitle by lazy { detailContainer2.title }
private val wantedDescription by lazy { detailContainer2.description }
Always working one:
private lateinit var foundTitle: TextView
private lateinit var foundDescription: TextView
private lateinit var wantedTitle: TextView
private lateinit var wantedDescription: TextView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
foundTitle = detailContainer1.title
foundDescription = detailContainer1.description
wantedTitle = detailContainer2.title
wantedDescription = detailContainer2.description
}
Thanks in advance
Lazy is mainly used when you want to access some read-only property because the same object is accessed throughout.
lateinit can only be used with a var property whereas lazy will always be used with val property. A lateinit property can be reinitialised again and again as per the use whereas the lazy property can only be initialised once.
Example. In this example, we will declare a lazy variable "myName" and we could see that the call to this parts of the code will happen only once and when the value is initialized, it will remember the value throughout the application. Once the value is assigned using lazy initialization, it cannot be reassigned .
Lazy Properties. It's a common pattern in software engineering to put off creating and initializing an object until it is actually needed. This pattern is known as lazy initialization, and is especially common on Android, since allocating a lot of objects during app startup can lead to a longer startup time.
Note that the type of myName$delegate is Lazy, not String. In the constructor, LazyKt.lazy () is assigned to myName$delegate. LazyKt.lazy () is responsible for executing the given initialization block.
Simply, lazy creates an instance that performs initialization at the first access to the property value, stores the result, and returns the stored value. Let's write a simple Kotlin code to check the implementation of lazy. If you do decompiling it to Java code, you can see the following code:
What’s Delegation? In general, Delegation refers to passing responsibility of one to another in order to achieve code- reuse in Object Oriented Programming. It prevents implementing the same code again and again.
The first call of getter executes a lambda passed to lazy () and stores its result. Subsequently, the getter execution returns the stored value. Simply, lazy creates an instance that performs initialization at the first access to the property value, stores the result, and returns the stored value.
Fragment's have their view destroyed when they get removed - but lazy
fields do not clear their reference so they are essentially leaking previous view.
If possible You should always have unique view IDs within your project, even if they are not within same layout - having duplicates can cause multiple problems (like yours).
If you were able to use kotlin extensions directly, it would generate code for finding, caching and clearing the view cache when fragments view is destroyed automatically.
Try to "get" views from fragments cache instead of assigning them to fields:
private val foundTitle
get() = detailContainer1.title
private val foundDescription
get() = detailContainer1.description
private val wantedTitle
get() = detailContainer2.title
private val wantedDescription
get() = detailContainer2.description
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With