Skip to content

Instantly share code, notes, and snippets.

异步流

挂起函数异步返回一个值, 而 Kotlin 的异步流返回多个值, 与 RxJava 中的流类似.

序列 (Sequences)

首先介绍一个数据类型, 序列(Sequences)表示一个延迟计算( lazily evaluated )的集合. 这里延迟即意味着异步, 或者惰性求值. 要取得它的值, 迭代它即可, 它有返回一个迭代器 (Iterator) 的方法, 所以可以在迭代器上进行各种方便的操作, 如filter,take, map 等. 因为它是惰性求值的, 所以这个集合的元素可能是无限的. 那怎么创建一个序列呢? 可以通过顶层序列构建函数或者扩展函数, 非常方便.

fun foo(): Sequence<Int> = sequence { // 序列构建器
 for (i in 1..3) {

Dart 类

Dart 是面向对象语言, 使用基于 mixin 的继承方式. 所有类都是 Object 类的子类.

构造函数

构造函数名称可以是 ClassNameClassName.identifier。后者称为命名构造函数. 例如,以下代码使用 Point()Point.fromJson() 构造函数创建 Point 对象:

var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});

Kotlin 通道

Deferred 值提供了一种在协程之间传递单个值的方便手段, 而 Channel 提供一种传递一系列值(即 Stream 流)的方法.

Channel 基础

Channel 概念上与Java的 BlockingQueue 很相似, 但有一个重要的不同点, BlockingQueueputtake 方法是阻塞的, 而Channel对应的 sendreceive 方法是可挂起.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*

Kotlin 协程实现原理

从一个例子开始

命令模式 (Direct Style)

fun main() {
    postItem(Item("item"))
}

fun postItem(item: Item) {

Kotlin 协程教程

什么是协程

协程就像非常轻量级的线程。线程是由系统调度的,线程切换或线程阻塞的开销都比较大。而协程依赖于线程,但是协程挂起时不需要阻塞线程,几乎是无代价的,协程是由开发者控制的。所以协程也像用户态的线程,非常轻量级,一个线程中可以创建任意个协程。

协程的创建

线程的创建方式主要有两种, 继承Thread, 或者实现Runnable接口, 而协程而是通过构建器(coroutine builder方法), 有点类似工厂方法, 调用一个静态工厂方法就可以返回一个协程.
coroutine builder 方法有: launch,async,runBlocking等, 就像运行线程时, 给它指定一个线程池, 放在那种线程池中运行. 协程运行也需要指定一个运行环境和条件, 这里专业的名称是: 协程范围(CoroutineScope), 上面提到的构建器方法都是定义在它上的扩展函数. 它包含一个上下文(coroutineContext), 上下文是保存协程运行时需要的一些基础信息, 如名字, 调度器, 子协程等, 它的是类似 Map 的数据结构.

使用 构建器 创建协程, 注意构建器的使用方法:

Android 如何使用协程

安卓上, 协程可以帮忙解决两大问题:

  • 管理长时间运行的任务, 这些任务可能阻塞主线程, 导致 UI 卡顿.
  • 在主线程上安全地调用网络或磁盘操作.

安卓上使用协程的最好方式是使用官方的架构组件, 它们提供了对协程的支持. 目前 ViewModel, Lifecycle, LiveData , Room 组件提供了对协程一等的支持.

ViewModelScope

ViewModel 的支持主要是在 ViewModel 上提供了一个称为 ViewModelScopeCoroutineScope , 所有在 ViewModelScope 上启动的协程, 当 ViewModelScope 销毁时自动取消. 这样可以有效防止忘记取消任务时导致的资源泄漏.

Android Paint 详解

Paint 基础

设置颜色

paint.setColor(int color)
paint.setARGB(int a, int r, int g, int b)

然后使用Paint 来绘制基本图形, 如 canvas.drawRect() , canvas.drawLine() , canvas.drawText() .

Skia 2D 基础

https://skia.org/user/api/

Skia 是围绕 SkCanvas 对象组织的。它是“绘制”方法的宿主对象,如它有 drawRectdrawPathdrawText 等绘制方法。这些方法都需要传入两个参数:正在绘制的图元(SkRectSkPath等)和颜色/样式属性(SkPaint)。

canvas->drawRect(rect, paint);

画笔 paint 对象指示图元如何被绘制(如上例中,指的是矩形):矩形是什么颜色,是填充(filled)或描边(stroked)的,应该如何与先前绘制的颜色融合(blend)。

@linsea
linsea / FullWidthDialog.txt
Last active June 26, 2019 03:26
full width dialog
1. https://stackoverflow.com/questions/28513616/android-get-full-width-for-custom-dialog
2. 还有一个技巧是在 DialogFragmnet 的 onStart() 方法里设置 window 的属性, 如下的答案有提到:
https://stackoverflow.com/questions/2306503/how-to-make-an-alert-dialog-fill-90-of-screen-size
3. 需求是屏幕最底下弹出一个包含 EditText 的 Dialog, 并且宽度占满屏幕的宽度, 点击输入框后, 输入法把 Dialog 顶上来. 实现如下.
i) Dialog 的内容布局使用 android:layout_gravity="bottom" 属性, 因为系统给 dialog 的父布局是一个 FrameLayout, 这样内容子布局就对齐到了屏幕的底部.
ii) 创建 Dialog:
@linsea
linsea / Loga.kts
Created August 10, 2018 09:34
Log分析统计脚本
import java.io.File
import java.lang.System.exit
import java.text.SimpleDateFormat
import java.util.*
if (args.size != 3) {
println("使用方法: kotlinc -script logst.kts <input_log_file_path> <output_file_path> <regex_pattern>")
println("注意 <regex_pattern> 中的正则使用'|'分隔重点LOG行, 第一个和最后一个必须为一次统计的开始行和结束行正则, 否则无法分辨一次统计的起始点与终止点")
exit(1)
}