变量声明

val 用于值从不更改的变量。使用 val 声明的变量无法重新赋值。
var 用于值可以更改的变量。

  1. var count: Int = 10
  2. val languageName: String = "Kotlin"

匿名函数

val stringLengthFunc: (String) -> Int = { input ->
    input.length
}

高阶函数

将其他函数用作参数的函数称为“高阶函数”。

fun changeState(state : String, mapSate : (String) -> Int) : Int{
    return mapState(state)
}

伴生对象

伴生对象提供了一种机制,用于定义在概念上与某个类型相关但不与某个特定对象关联的变量或函数。伴生对象类似于对变量和方法使用 Java 的 static 关键字。

class LoginFragment : Fragment() {

    companion object {
        private const val TAG = "LoginFragment"
    }
}

协程

suspend

用于暂停执行当前协程,并保存所有局部变量

suspend fun getData(){
    val result = sendParams()
    show(result)
}

withContext

使用协程库中的 withContext() 函数将协程的执行操作移至其他线程,确保主线程安全

suspend fun sendParams(){
    return withContext(Dispatchers.IO){
        //    此作用域的代码,将在 IO 线程执行
    }
}

resume

用于让已挂起的协程从挂起处继续执行

CoroutineScope

CoroutineScope 会跟踪它使用 launch 或 async 创建的所有协程。可以随时调用 scope.cancel() 以取消正在进行的工作(即正在运行的协程)。与调度程序不同,CoroutineScope 不运行协程。

CoroutineContext

  - Job:控制协程的生命周期。
  - CoroutineDispatcher:将工作分派到适当的线程。
  - CoroutineName:协程的名称,可用于调试。
  - CoroutineExceptionHandler:处理未捕获的异常。
class Demo{

    val scope = CoroutineScope(Job() + Dispatchers.Main)

    fun launch(){
        val job1 = scope.launch{

        }
        //    job2 会覆盖 job1 
        //    因为系统始终会向新协程分配 Job 的新实例
        val job2 = scope.launch(Dispatchers.Default + "BackgroundCoroutine"){

        }
    }

    //    取消协程
    fun clean(){
        scope.cancel()
    }
}

调度程序

Kotlin 协程使用调度程序确定哪些线程用于执行协程。要在主线程之外运行代码,可以让 Kotlin 协程在 Default 或 IO 调度程序上执行工作。在 Kotlin 中,所有协程都必须在调度程序中运行,即使它们在主线程上运行也是如此。协程可以自行挂起,而调度程序负责将其恢复。

  • Dispatchers.Main - 使用此调度程序可在 Android 主线程上运行协程。此调度程序只能用于与界面交互和执行快速工作。
  • Dispatchers.IO - 此调度程序经过了专门优化,适合在主线程之外执行磁盘或网络 I/O。
  • Dispatchers.Default - 此调度程序经过了专门优化,适合在主线程之外执行占用大量 CPU 资源的工作。

    启动协程

  • launch 可启动新协程而不将结果返回给调用方。任何被视为“一劳永逸”的工作都可以使用 launch 来启动。

  • async会启动一个新的协程,并允许您使用一个名为 await 的挂起函数返回结果。

    数据流

    flow 构建器函数会创建一个新数据流,可使用 emit 函数手动将新值发送到数据流中。

  • 数据流是有序的。当协程内的提供方调用挂起函数时,提供方会挂起,直到挂起函数返回。在此示例中,提供方会挂起,直到 fetchLatestNews 网络请求完成为止。只有这样,请求结果才会发送到数据流中。

  • 使用 flow 构建器时,提供方不能提供来自不同 CoroutineContext 的 emit 值。因此,请勿通过创建新协程或使用 withContext 代码块,在不同 CoroutineContext 中调用 emit。在这些情况下,可使用其他数据流构建器,例如 callbackFlow。

    创建数据流

    ```kotlin class NewsRemoteDataSource( private val newsApi: NewsApi, private val refreshIntervalMs: Long = 5000 ) { val latestNews: Flow> = flow {
      while(true) {
          val latestNews = newsApi.fetchLatestNews()
          emit(latestNews)
          delay(refreshIntervalMs) // Suspends the coroutine for some time
      }
    
    } }

// Interface that provides a way to make network requests with suspend functions interface NewsApi { suspend fun fetchLatestNews(): List }

<a name="oVFBr"></a>
## 修改数据流
```kotlin
class NewsRepository(
    private val newsRemoteDataSource: NewsRemoteDataSource,
    private val userData: UserData
) {

    val favoriteLatestNews: Flow<List<ArticleHeadline>> =
        newsRemoteDataSource.latestNews

            .map { news -> news.filter { userData.isFavoriteTopic(it) } }

            .onEach { news -> saveInCache(news) }
}

收集数据流

class LatestNewsViewModel(
    private val newsRepository: NewsRepository
) : ViewModel() {

    init {
        viewModelScope.launch {

            newsRepository.favoriteLatestNews.collect { favoriteNews ->

            }
        }
    }
}