2023-02-21

Java

Kotlin

官方文档 From Java To Kotlin, git 菜鸟教程-Kotlin 类和对象

基本语法

变量

Constants and Variables

Java

String name = "Amit Shekhar";
final String name = "Amit Shekhar";

Kotlin

var name = "Amit Shekhar"
val name = "Amit Shekhar"
 
 

Assigning the null value

Java

String otherName;
otherName = null;

Kotlin

var otherName : String?
otherName = null

List

kotlin 列表元素分为: arrayOf 为不可变, Mutable 可变.

// arrayOf 为不可变
var riversArray = arrayOf("Nile", "Amazon", "Yangtze")
// 使用 += 赋值操作创建了一个新的 riversArray,
// 复制了原始元素并添加了“Mississippi”
riversArray += "Mississippi"
println(riversArray.joinToString())
 
 
 
// Mutable 为可变
var mutableList = mutableListOf("")
 
 

Verify if value is null 避免空指针 (?.)

https://kotlinlang.org/docs/kotlin-tour-null-safety.html#nullable-types

Java

if (text != null) {
  int length = text.length();
}

Kotlin

text?.let {
    val length = text.length
}
// or simply
val length = text?.length
 
/////////// null 默认值操作
val name: String? = // 可能为 null 的字符串
// 如果 name 不为 null,则使用 name,否则使用默认值 "Guest"
val result: String = name ?: "Guest"
 
/////////// ?.let 操作符
name?.let {
    // 在这里,name 不为空时执行
    println("Name is $it")
}
 
/////////// Elvis 操作符
val user: User? = getUser()
// 如果 user 或 user.email 为 null,则使用默认值 "unknown"
val email: String = user?.email ?: "unknown"
 
 
/////////// 确定不会为 `null`,你可以使用非空断言运算符(`!!`)
//当你使用 `!!` 运算符时,如果该值是 `null`,它将抛出一个 `NullPointerException`。
val str: String? = "Hello, World!" 
val nonNullStr: String = str!! // 如果 str 为 null,则会抛出异常
 

数组与反射

// 对应 java 的 String[] strings = {"a",  "b"}
val strings = arrayOf("a","b")
 
// 对应 java 的 Integer[] 
val results = Array(3){ i-> 0}
 
 
// 对应 java 的 Class[]  cls = {ServicePathPlan.class}
val paramType = Array<ServicePathPlan>::class.java
 
// 对应 java 的 Class[]  cls = {Object.class}
val paramType = Array<Any>::class.java
 

lateinit 关键字

lateinit 关键字用来修饰一个类的非空成员变量,表示该成员变量的值在稍后合适的时机会初始化,例如:

class Test {
	lateinit var name: String
	
	fun test() {
		if (::name.isInitialized) {
			println("name is initialized")
		}
		println(name)
	}
}

在给 lateinit 修饰的成员变量赋值之前如果有代码试图访问该成员变量的值,则会直接抛出异常。在访问 lateinit 修饰的成员变量之前可以先用 isInitialized 来判断该成员变量是否已经赋值了。

类型转换 as

val obj: Any = "This is a string" 
// 将 obj 强制转换为 String 类型 
val str: String = obj as String
 
//null 可用
val str: String = obj as? String
 
 

Verify if value is NotNull OR NotEmpty

Java

String sampleString = "Shekhar";
if (!sampleString.isEmpty()) {
    myTextView.setText(sampleString);
}
if(sampleString!=null && !sampleString.isEmpty()){
    myTextView.setText(sampleString); 
}

Kotlin

var sampleString ="Shekhar"
if(sampleString.isNotEmpty()){  //the feature of kotlin extension function
    myTextView.text=sampleString
}
if(!sampleString.isNullOrEmpty()){
   myTextView.text=sampleString 
}

Concatenation(拼接) of strings

Java

String firstName = "Amit";
String lastName = "Shekhar";
String message = "My name is: " + firstName + " " + lastName;

Kotlin

var firstName = "Amit"
var lastName = "Shekhar"
var message = "My name is: $firstName $lastName"

文本行

Java

String text = "First Line\n" +
	  "Second Line\n" +
	  "Third Line";

Kotlin

val text = """
        |First Line
        |Second Line
        |Third Line
        """.trimMargin()

Substring

Java

String str = "Java to Kotlin Guide";
String substr = "";
 
//print java
substr = str.substring(0, 4);
System.out.println("substring = " + substr);
 
//print kotlin
substr = str.substring(8, 14);
System.out.println("substring = " + substr);

Kotlin

var str = "Java to Kotlin Guide"
var substr = ""
 
//print java
substr = str.substring(0..3) //
println("substring $substr")
 
//print kotlin
substr = str.substring(8..13)
println("substring $substr")

Bitwise Operators

Java

final int andResult  = a & b;
final int orResult   = a | b;
final int xorResult  = a ^ b;
final int rightShift = a >> 2;
final int leftShift  = a << 2;
final int unsignedRightShift = a >>> 2;

Kotlin

val andResult  = a and b
val orResult   = a or b
val xorResult  = a xor b
val rightShift = a shr 2
val leftShift  = a shl 2
val unsignedRightShift = a ushr 2

流程控制

IF 表达式

// 传统用法
var max = a 
if (a < b) max = b
 
// 使用 else 
var max: Int
if (a > b) {
    max = a
} else {
    max = b
}
 
// 作为表达式
val max = if (a > b) a else b
 
//也可以把 IF 表达式的结果赋值给一个变量。
val max = if (a > b) {
    print("Choose a")
    a
} else {
    print("Choose b")
    b
}
 
// 区间 
fun main(args: Array<String>) {
    val x = 5
    val y = 9
    if (x in 1..8) {
        println("x 在区间内")
    }
}
 

When 表达式

when 将它的参数和所有的分支条件顺序比较,直到某个分支满足条件。

when 既可以被当做表达式使用也可以被当做语句使用。如果它被当做表达式,符合条件的分支的值就是整个表达式的值,如果当做语句使用, 则忽略个别分支的值。

when 类似其他语言的 switch 操作符。其最简单的形式如下:

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> { // 注意这个块
        print("x 不是 1 ,也不是 2")
    }
}

在 when 中,else 同 switch 的 default。如果其他分支都不满足条件将会求值 else 分支。

如果很多分支需要用相同的方式处理,则可以把多个分支条件放在一起,用逗号分隔:

when (x) {
    0, 1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}

我们也可以检测一个值在(in)或者不在(!in)一个区间或者集合中:

when (x) {
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}

另一种可能性是检测一个值是(is)或者不是(!is)一个特定类型的值。注意: 由于智能转换,你可以访问该类型的方法和属性而无需 任何额外的检测。

fun hasPrefix(x: Any) = when(x) {
    is String -> x.startsWith("prefix")
    else -> false
}

when 也可以用来取代 if-else if链。 如果不提供参数,所有的分支条件都是简单的布尔表达式,而当一个分支的条件为真时则执行该分支:

when {
    x.isOdd() -> print("x is odd")
    x.isEven() -> print("x is even")
    else -> print("x is funny")
}

循环(For-loops)

Java

for (int i = 1; i <= 10 ; i++) { }
 
for (int i = 1; i < 10 ; i++) { }
 
for (int i = 10; i >= 0 ; i--) { }
 
for (int i = 1; i <= 10 ; i+=2) { }
 
for (int i = 10; i >= 0 ; i-=2) { }
 
for (String item : collection) { }
 
for (Map.Entry<String, String> entry: map.entrySet()) { }

Kotlin

for (i in 1..10) { }
 
for (i in 1 until 10) { }
 
for (i in 10 downTo 0) { }
 
for (i in 1..10 step 2) { }
 
for (i in 10 downTo 0 step 2) { }
 
for (item in collection) { }
 
for ((key, value) in map) { }

循环(for each)

Java

// Java 7 and below
for (Car car : cars) {
  System.out.println(car.speed);
}
 
// Java 8+
cars.forEach(car -> System.out.println(car.speed));
 
// Java 7 and below
for (Car car : cars) {
  if (car.speed > 100) {
    System.out.println(car.speed);
  }
}
 
// Java 8+
cars.stream().filter(car -> car.speed > 100).forEach(car -> System.out.println(car.speed));
cars.parallelStream().filter(car -> car.speed > 100).forEach(car -> System.out.println(car.speed));

Kotlin

cars.forEach {
    println(it.speed)
}
 
cars.filter { it.speed > 100 }
      .forEach { println(it.speed)}
 
// kotlin 1.1+
cars.stream().filter { it.speed > 100 }.forEach { println(it.speed)}
cars.parallelStream().filter { it.speed > 100 }.forEach { println(it.speed)}

异常处理

 try {
	// 尝试执行的代码块,可能会抛出异常
	throwException()
} catch (e: ArithmeticException) {
	// 处理ArithmeticException异常
	println("捕获到算术异常:${e.message}")
} catch (e: Exception) {
	// 处理其他类型的异常
	println("捕获到异常:${e.message}")
} finally {
	// 无论是否发生异常,都会执行的代码
	println("最终块:执行清理工作")
}
 

**try close **

// 正确
FileInputStream("file.txt").use { /* ... */ }

函数定义

 
// 函数定义使用关键字 fun,参数格式为:参数 : 类型
fun sum(a: Int, b: Int): Int {   // Int 参数,返回值 Int
    return a + b
}
// 若只有一行 可忽略 {}
fun sum(a: Int, b: Int) = a + b
 
// public 方法则必须明确写出返回类型
public fun sum(a: Int, b: Int): Int = a + b   
 
//无返回值的函数(类似Java中的void):  在 Kotlin 中,`Unit` 是一个特殊的类型,用于表示“没有有意义的值返回”。它类似于 Java 中的 `void`。
fun printSum(a: Int, b: Int): Unit { 
    print(a + b)
}
 
// 如果是返回 Unit类型,则可以省略(对于public方法也是这样):
public fun printSum(a: Int, b: Int) { 
    print(a + b)
}
//函数的变长参数可以用 vararg 关键字进行标识
fun vars(vararg v:Int){
    for(vt in v){
        print(vt)
    }
}
 
// 测试
fun main(args: Array<String>) {
    vars(1,2,3,4,5)  // 输出12345
}
 

lambda 表达式

常用定义

// { 参数列表 -> 函数体 }
fun main(args: Array<String>) {
    val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
    println(sumLambda(1,2))  // 输出 3
}
 
 
// 无参 无返回值
fun main(args: Array<String>) {
    val greeting = { println("Hello!")}
    //调用函数
    greeting()
}
 
//如果Lambda表达式,并且该参数的类型可以从上下文中推断出来,则可以"it"来引用该参数
arrayOf(1,3,6,74).forEach { println(it) }
// 或者指定名称 
arrayOf(1,3,6,74).forEach { ele ->println(ele) }
 
// 带参数和返回类型的Lambda
// 下面的程序具有一个lambda表达式,该表达式接受两个整数作为参数,并返回这两个整数的乘积。
fun main(args: Array<String>) {
    val product = { a: Int, b: Int -> a * b }
    val result = product(93)
    println(result)
}
 
//线程 Runnable 
mRunnable = Runnable {  
	println("ha")  
}

匿名对象 + 方法覆盖

// 匿名对象 + 方法覆盖
val adapter = object: SimpleAdapter(this, listMap,R.layout.map_layers_list_item, from, to){  
	override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {  
		return view  
	}
}

label@ 标签用法

wim.webContext.connectDeviceManager.ifPresent outer@{ cdm ->
		cdm.getConnectedDevice().ifPresent inerer@{ connectedDevice ->
			// 假设这里是你的逻辑
			if (1==1) {
				// 使用带有标签的 return 来跳出外层函数
				return@inerer
			}
		}
		return@outer
	}

集合操作

创建集合

// 创建一个可变列表
val mutableList = mutableListOf(1, 2, 3, 4, 5)
 
// 创建一个不可变列表
val immutableList = listOf("apple", "banana", "orange")
 
// 创建一个可变映射(键值对)
val mutableMap = mutableMapOf(1 to "one", 2 to "two", 3 to "three")
 
// 创建一个不可变映射
val immutableMap = mapOf("key1" to "value1", "key2" to "value2")
 

遍历集合

val numbers = listOf(1, 2, 3, 4, 5)
 
// 遍历列表
for (number in numbers) {
    println(number)
}
 
// 使用 forEach 遍历列表
numbers.forEach { println(it) }
 
// 遍历映射
val map = mapOf("a" to 1, "b" to 2, "c" to 3)
for ((key, value) in map) {
    println("Key: $key, Value: $value")
}
 
// 带索引
list.forEachIndexed { index, item ->
	println("索引 $index : $item")
}

过滤和转换集合

val numbers = listOf(1, 2, 3, 4, 5)
 
// 过滤列表
val evenNumbers = numbers.filter { it % 2 == 0 }
println("Even numbers: $evenNumbers")
 
// 映射列表
val squaredNumbers = numbers.map { it * it }
println("Squared numbers: $squaredNumbers")
 
//过滤和收集
val filteredContent = content.filter { it.id.isNullOrBlank() }.toCollection(mutableListOf())
 

排序集合

val numbers = listOf(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5)
 
// 升序排序
val sortedNumbers = numbers.sorted()
println("Sorted numbers: $sortedNumbers")
 
// 自定义排序
val sortedByLength = numbers.sortedBy { it.toString().length }
println("Sorted by length: $sortedByLength")
 

其他集合操作

val numbers = listOf(1, 2, 3, 4, 5)
 
// 判断是否包含特定元素
val containsThree = numbers.contains(3)
println("Contains 3? $containsThree")
 
// 求和
val sum = numbers.sum()
println("Sum: $sum")
 
// 查找最大值和最小值
val max = numbers.maxOrNull()
val min = numbers.minOrNull()
println("Max: $max, Min: $min")
 

类和对象

菜鸟教程-Kotlin 类和对象

普通类

class Runoob() {
// Kotlin 中的类可以有一个 主构造器,以及一个或多个次构造器,主构造器是类头部的一部分,位于类名称之后:
 
// 主构造器
 init {
	println("name is $name")
}
 
 //次构造器
 //如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字:
 constructor(parent: Person) {
        parent.children.add(this) 
}
 
//类属性
var name: String =...
var url: String = ...
var city: String = ...
 
fun foo() { print("Foo") } // 成员函数
}
 
 
 

数据类 (DTO)

类似java的 record data class Developer(var name: String, var age: Int)

data class JsMessage(val topic: String, val payload: String) {
    companion object{
        fun fromString(msg: String): JsMessage {
            val jsonObject: JSONObject = JSONObject(msg)
            val topic = jsonObject.getString("topic")
            val payload = jsonObject.getString("payload")
            return JsMessage(topic, payload)
        }
    }
 
    override fun toString(): String {
        val jsonObject = JSONObject()
        jsonObject.put("topic", topic)
        jsonObject.put("payload", payload)
        return jsonObject.toString();
    }
}

解构声明

为数据类生成的 component 函数 使它们可在解构声明中使用:

val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") 

Generics (泛型)

Java

// Example #1
interface SomeInterface<T> {
    void doSomething(T data);
}
 
class SomeClass implements SomeInterface<String> {
    @Override
    public void doSomething(String data) {
        // some logic
    }
}
 
// Example #2
interface SomeInterface<T extends Collection<?>> {
    void doSomething(T data);
}
 
class SomeClass implements SomeInterface<List<String>> {
 
    @Override
    public void doSomething(List<String> data) {
        // some logic
    }
}

Kotlin

interface SomeInterface<T> {
    fun doSomething(data: T)
}
 
class SomeClass: SomeInterface<String> {
    override fun doSomething(data: String) {
        // some logic
    }
}
 
interface SomeInterface<T: Collection<*>> {
    fun doSomething(data: T)
}
 
class SomeClass: SomeInterface<List<String>> {
    override fun doSomething(data: List<String>) {
        // some logic
    }
}

Anonymous Class

Java

 AsyncTask<Void, Void, Profile> task = new AsyncTask<Void, Void, Profile>() {
    @Override
    protected Profile doInBackground(Void... voids) {
        // fetch profile from API or DB
        return null;
    }
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // do something
    }
};

Kotlin

val task = object : AsyncTask<Void, Void, Profile>() {
    override fun doInBackground(vararg voids: Void): Profile? {
        // fetch profile from API or DB
        return null
    }
    override fun onPreExecute() {
        super.onPreExecute()
        // do something
    }
}
 
//////// 比如 Runnable
val t = thread { object: Runnable{
		public override fun run() {
			println("Hello World!  for thread")
		}
	}
}
t.start()

枚举

Java

public enum Direction {
        NORTH(1),
        SOUTH(2),
        WEST(3),
        EAST(4);
 
        int direction;
 
        Direction(int direction) {
            this.direction = direction;
        }
 
        public int getDirection() {
            return direction;
        }
    }

Kotlin

enum class Direction(val direction: Int) {
    NORTH(1),
    SOUTH(2),
    WEST(3),
    EAST(4);
}
// 可以理解为 枚举类中的 NORTH, SOUTH 元素 继承了Direction, 所以它们都有direction属性

继承

Kotlin 中所有类都继承该 Any 类,它是所有类的超类,对于没有超类型声明的类是默认超类:

Any 默认提供了三个函数, 注意:

equals()
hashCode()
toString()

Any 不是 java.lang.Object。

如果一个类要被继承,可以使用 open 关键字进行修饰。

open class Base(p: Int)           // 定义基类
 
class Derived(p: Int) : Base(p)
// 如果子类有主构造函数, 则基类必须在主构造函数中立即初始化。
open class Person(var name : String, var age : Int){// 基类
 
}
 
// 类似C++ 委托构造
class Student(name : String, age : Int, var no : String, var score : Int) : Person(name, age) {
 
}

扩展 (类似JS的原型链)

Kotlin 可以对一个类的属性和方法进行扩展,且不需要继承或使用 Decorator 模式。

  • 扩展是一种静态行为,对被扩展的类代码本身不会造成任何影响。
  • 扩展函数不能访问被扩展类的私有成员。这是因为扩展函数实际上是在类的外部定义的,它没有像类的成员函数那样的访问权限。
  • 如果在多个地方定义了同名的扩展函数,Kotlin 会根据导入的情况和调用的上下文来确定使用哪一个扩展函数。这可能会导致一些意想不到的行为,所以在定义和使用扩展函数时要注意命名冲突的问题。
class User(var name:String)
 
/**扩展函数, 类似 js 的原型链?**/
fun User.Print(){
    print("用户名 $name")
}
 
fun main(arg:Array<String>){
    var user = User("Runoob")
    user.Print()
}

组合对象 (companion object)

在 Kotlin 中,companion object 是一个对象声明,允许在类内部创建一个与类相关联的单例对象。它类似于 Java 中的静态成员,但在很多方面更加灵活和强大。

  1. 访问权限:可以访问类的私有成员。
  2. 命名:不需要额外命名,直接使用 companion object
  3. 访问方式:可以通过类名直接访问其内部的 companion object 成员,而不需要实例化类。
  4. 继承:不能继承自其他类或对象,因为它本身就是一个单例对象。
class MyClass {
    companion object {
        // 在这里定义的成员可以通过类名直接访问
        fun myFunction() {
            println("This is a function inside companion object")
        }
    }
}

// MyClass.myFunction() // 调用 companion object 中的函数

单例对象(single object)

Kotlin 中我们可以方便 使用 object 关键字 声明来获得一个单例。

object DataProviderManager {
    fun registerDataProvider(provider: DataProvider) {
        // ……
    }
 
    val allDataProviders: Collection<DataProvider>
        get() = // ……
}
 

协程(Coroutines)

Kotlin 中的协程提供了一种全新处理并发的方式,可以在 Android 平台上使用它来简化异步执行的代码。协程是从 Kotlin 1.3 版本开始引入,但这一概念在编程世界诞生的黎明之际就有了,最早使用协程的编程语言可以追溯到 1967 年的 Simula 语言。

在 Android 平台上,协程主要用来解决两个问题:

  1. 处理耗时任务 (Long running tasks),这种任务常常会阻塞住主线程;
  2. 保证主线程安全 (Main-safety) ,即确保安全地从主线程调用任何 suspend 函数。 https://developer.android.google.cn/kotlin/coroutines?hl=zh_cn
dependencies {
    // Kotlin
    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.32"
 
    // 协程核心库
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3"
    // 协程Android支持库
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3"
    // 协程Java8支持库
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.4.3"
 
    // lifecycle对于协程的扩展封装
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
    
}

创建协程

协程需要在一个作用域内启动。常见的作用域包括:

作用域

  • GlobalScope:全局作用域,不推荐用于大多数情况,因为它不会自动取消,可能导致内存泄漏。
  • viewModelScope:在 ViewModel 中使用,当 ViewModel 被清除时,所有协程都会自动取消。
  • lifecycleScope:在 Activity 或 Fragment 中使用,与生命周期绑定,当生命周期结束时,所有协程会自动取消。
  • CoroutineScope:自定义作用域,适用于特定场景。

GlobalScope.launch/async{} - 全局启动的协程存在启动协程后的组件若被销毁, 但协程还存在的情况,极限情况下可能导致资源耗尽,因此并不推荐这样启动

viewModelScope

class LoginViewModel(
    private val loginRepository: LoginRepository
): ViewModel() {
 
    fun login(username: String, token: String) {
        // Create a new coroutine to move the execution off the UI thread
        viewModelScope.launch(Dispatchers.IO) {
            val jsonBody = "{ username: \"$username\", token: \"$token\"}"
            loginRepository.makeLoginRequest(jsonBody)
        }
    }
}

viewModelScope 是预定义的 CoroutineScope,包含在 ViewModel KTX 扩展中。请注意,所有协程都必须在一个作用域内运行。一个 CoroutineScope 管理一个或多个相关的协程。 launch 是一个函数,用于创建协程并将其函数主体的执行分派给相应的调度程序。 Dispatchers.IO 指示此协程应在为 I/O 操作预留的线程上执行。

调度器(Coroutine Dispatcher)

协程可以在不同的线程上执行,常见的调度器包括:

  • Dispatchers.Main:在主线程(UI 线程)上执行,适合更新 UI。
  • Dispatchers.IO:在 I/O 线程上执行,适合处理 I/O 操作(如网络请求、文件读写、数据库操作)。
  • Dispatchers.Default:在默认线程池上执行,适合 CPU 密集型任务。
  • Dispatchers.Unconfined:不受限调度器,通常不推荐使用。

suspend 关键字

挂起函数是一种可以被暂停和恢复的函数,它使用 suspend 关键字进行声明。 它们不会阻塞线程, 只是给使用者的提醒:我是一个耗时函数, 我被我的创建者用挂起的方式放在后台运行,所以请在协程里调用我。 挂起的操作 —— 也就是切线程,依赖的是挂起函数里面的实际代码,而不是这个关键字。 所以这个关键字,只是一个声明。

withContext

如果只是使用 launch 函数,协程并不能比线程做更多的事。不过协程中却有一个很实用的函数:withContext 。这个函数可以切换到指定的线程(调度器),并在闭包内的逻辑执行结束之后,自动把线程切回去继续执行。

CoroutineScope(Dispatchers.Main).launch {      // 👈 在 UI 线程开始
    val image = withContext(Dispatchers.IO) {  // 👈 切换到 IO 线程,并在执行完成后切回 UI 线程
        getImage(imageId)                      // 👈 将会运行在 IO 线程
    }
    avatarIv.setImageBitmap(image)             // 👈 回到 UI 线程更新 UI
}
 
 
private suspend fun syncMapLayersConfig(){  
	// 从配置中拿  
	var localLayersConfig = withContext(Dispatchers.IO){ getLocalLayersConfig() }  
	setMapLayersConfig(localLayersConfig )  
}

委托

https://www.runoob.com/kotlin/kotlin-delegated.html

委托模式 (简而言之, 就是代理模式) 是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。

Kotlin 直接支持委托模式,更加优雅,简洁。Kotlin 通过关键字 by 实现委托。

属性委托

属性委托指的是一个类的某个属性值不是在类中直接进行定义,而是将其托付给一个代理类,从而实现对该类的属性统一管理。

val/var <属性名>: <类型> by <表达式>

import kotlin.reflect.KProperty
// 定义包含属性委托的类
class Example {
    var p: String by Delegate()
}
 
// 委托的类
class Delegate {
 
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, 这里委托了 ${property.name} 属性"
    }
 
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$thisRef 的 ${property.name} 属性赋值为 $value")
    }
}
fun main(args: Array<String>) {
    val e = Example()
    println(e.p)     // 访问该属性,调用 getValue() 函数
 
    e.p = "Runoob"   // 调用 setValue() 函数
    println(e.p)
}