kotlin entrustment
On the introduction of delegation, I will explain the most commonly used ways to implement delegation with several examples of my own implementation. The description will be very clear and easy to understand.
In particular, the Lazy initialization method of the inherited Lazy class in the ViewModel extension library in android will be simply simulated to help you better understand
Using delegates to implement inheritance
Delegate using the by keyword
- Code description
When calling the drive method of BrokenTaxi, the method call will be forwarded to the drive method of Taxi passed in by the formal parameter
The compiler will give priority to the replication method. For example, if our BrokenTaxi replicates the startupEngin method, it will not call the startupEngine method of Taxi
- Output results
Because BrokenTaxi indicates a broken taxi, the engine cannot be started. You need to rewrite startupEngine. When the user wants to start the engine, he will tell him that it cannot be started
Standard entrustment
Delay attribute
Initialize on first visit
Lazy will accept a lambda and return a function of a lazy instance. The returned instance can be used as a delegate to implement the delay attribute. When the attribute is used for the first time, the return value of the lambda expression will be passed to the attribute
By default, the initialization of the delay attribute is carried out in the synchronization lock, and this value can be observed by all threads.
If you are sure that initialization will always occur on the same thread as the property, you can use lazythreadsafetymode None mode: it will not have any thread safety guarantee and related overhead. The implementation code is as follows:
val laze2 :String by lazy(LazyThreadSafetyMode.NONE){ "Android" }
Observable attribute
Listeners are notified of this property change
Observable attributes can be implemented in two ways: observable and vetoable
The observable method can receive a callback when the attribute changes;
The vetoable method can also receive callbacks, but when using vetoable, we can intercept according to conditions to decide whether to update the value of the attribute;
Create in observable mode
When we change the value of field, the lambda expression will be called back
Create using vetoable
It is also important to create observable attributes in vetoable mode. We can intercept them in lambda expression and decide whether to update the value of the attribute
Store attributes in mapping
We can use map mapping to delegate attributes. The key of map is the name of the delegated attribute, and the value of map is the value of the delegated attribute
Local delegate properties
Attribute delegation requirements
Attribute delegation should have been mentioned first, because I understood it very slowly when I first learned about delegation, so let's take a look at the previous things. It may be easier to accept attribute delegation here.
Property delegate must provide a getValue method. If it is a var property, it must also provide a setValue method
- Explanation of the basic principle of attribute delegation
- Property changes and method calls in delegate classes
For attribute delegation, if the delegated attribute field is set to var, the delegate class ResourceDelete needs to implement getValue and setValue methods at the same time.
Then I have the following questions:
1. Is the getValue method called every time we use the field attribute reference (answer: yes)
2. Is the setValue method called every time we change the field property reference (answer: yes)
There are too many codes. The screenshot can't be put down. Go to the code
After running the code, the verification of the above two conclusions will be released
class EnTrustObject { var field: Resource by ResourceDelete() } class ResourceDelete { var resource: Resource = Resource("Initial object") operator fun getValue(enTrustObject: EnTrustObject, property: KProperty<*>): Resource { println("Called getValue method") return resource } operator fun setValue(enTrustObject: EnTrustObject, property: KProperty<*>, resource: Resource) { this.resource = resource println("Called setValue method") } } class Resource(val value:String) { fun print() { println("$value Android print resources") } } fun main() { EnTrustObject().apply { field.print() field= Resource("Changed object") field.print() field.print() } }
Delegate using the Lazy class
Lazy's description
kotlin provides us with a Lazy class to help us realize more complex Lazy loading. I have translated the description of Lazy into screenshots as follows:
In other words, Lazy can help us do such a thing. The value of the attribute we want to obtain is stored in value, and the isInitialized method is provided to judge whether the attribute has been initialized.
If it has been initialized, the value will not be reset when we get the property with the following code.
private val engine: Engine by engine()
Lazy loading using lazy
We have made such an implementation:
Create a Car class. The Car class holds an engine class. The engine is initialized by lazy loading. See the code:
fun main() { Car().apply { myEngine() myEngine() myEngine() } } /** * Declare automobile class */ class Car { private val engine: Engine by engine()//Initializing the engine using extension functions fun myEngine() { engine.showIntroduce() } } /** * Declare engine class */ class Engine(private val describe: String) { fun showIntroduce() { println(describe) } } /** * Create an extension function to get the engine, */ fun Car.engine(): LazyEngine { return LazyEngine() } /** * Engine initialization class, Lazy class, generic engine class */ class LazyEngine : Lazy<Engine> { private var cache: Engine? = null /** * If the engine cache is not empty, it indicates that it has been initialized, otherwise it will not be initialized */ override fun isInitialized(): Boolean { return cache != null } /** * Get engine value */ override val value: Engine get() { val newValue = cache return if (newValue == null) {//When the engine is not created, the cache value will be returned if any Engine("Narrator(Android): Chang'an Mazda, twin turbocharged engine") } else { cache!! } } }
Code execution result:
For Lazy loading implemented in Lazy mode, if you want to learn more complex application scenarios, it is recommended that you read the source code of ViewModel initialization method in android ViewModel extension library, and you will receive a lot of goods
Finally, I brought myself a salt:
Welcome to learn more about my official account, "Ann Ann an Android".