/Kotlin

HenCoder Plus 学习 Kotlin 项目

Primary LanguageKotlin

# Kotlin

## 基础

1. MainActivity
2. CodeView
3. User

1:04:00 之后

4. Utils
5. CacheUtils
6. BaseApplication
7. @file:JvmName("xxx")
8. HttpClient

---

### 改造

#### 4. Utils 和 CacheUtils

- 静态函数
    - 定义在文件中: 如 Utils
    - Object:

#### 6. BaseApplication(1:16 ~ 1:18)
- companion object: 实现单例
    - @JvmStatic: 在里面的方法上加上注解, 在 Java 类中用类名. 调用即可

---

7. @file:JvmName("xxx")
   -给 Kotlin 文件使用,在第一行。 注解之后,就直接可以使用 文件名. 调用了。

8. HttpClient(1:21:40 ~)

9. Lesson(1:37 ~)

10. LessonPresenter(1:38 ~)
    - const: 编译器常量

11. LessonAdapter(1:46 ~)
    - 自动转换成 Kotlin 代码,onCreate 方法去掉 private 修饰

12. internal(1:49:30 ) -> LessonAdapter
    - 模块内访问修饰符
    - updateAndNotify() 用 interval 修饰
    - onBind() 用 interval 修饰
    - LessonActivity showResult() 用 interval 修饰

13. BaseViewHolder(1:50:00 ~)
    - 用 abstract 修饰
    - getView() 方法用 protected open 修饰

14. abstract, open, override
    - 被这些关键字修饰的类才可以被继承或者被重写
---

## 进阶

1. 主构造器
    - 直接卸载类的声明上
    - LessonAdapter -> LessonViewHolder
    - Lesson(2:20)
    - User(3:20)
    - CodeView(4:20)

2. init { ... }
    - 初始化代码块
    - Lesson(2:55)
    - User(3:20)
    - CodeView(4:20)

3. 自动 setter getter
    - (5:40)
    - Kotlin 中,字段修饰符不是 private,就会对成员变量自动 setter getter
    - Lesson 去掉 getter setter 方法

4. 定义变量时,通过主构造器参数初始化,不需要 init { ... }
    - Lesson(6:40)

5. 在主构造器中初始化
    - Lesson(7:05)

6. 改造 User
    - (9:00)

7. data class
    - (10:00)
    - 帮助生成 copy() 函数
    - 复制对象时,用 copy() 函数很方便
    - app/com.example.app.entity 新建 Test.kt

8. ==
    - 相当于 java 中的 equals()
    - (12:30)

9. ===
    - 比较对象地址值

10. Kotlin 反编译为 Java
    - Tools -> Kotlin -> Show Kotlin Bytecode

11. 简写(17:50) -> LessonAdapter_LessonViewHolder_onBind()
    - 前
     ```
      var date = lesson.date
                  if (date == null) {
                      date = "日期待定"
                  }
     ```
    - 后
     ```
        var date = lesson.date?: "日期待定"
     ```

12. 简写(19:30)
    - MainActivity verify()
    - 前: user.username != null && user!!.username!!.length < 4
    - 后: user.username?.length?: 0 < 4
        - user.username?.length => 等价于 user.username != null
        - user.username?.length?: 0 => 等价于 user.username?.length 时 null ,没搞明白
    - 可读性不高

13. when() 有返回值(21:00 ~)
    - LessonAdapter -> LessonViewHolder_onBind()

14. 操作符(22:40 ~)
    - operator: 用这个修饰的方法,可以直接用操作符调用

15. 集合遍历简化操作(23:30 ~ 27:00)
    - LessonPresenter -> showPlayBack()
     ```
        lessons.forEach {
                    if (it.state === Lesson.State.PLAYBACK) {
                        playbackLessons.add(it)
                    }
                }
                activity!!.showResult(playbackLessons)

                //简化2
                val filter = lessons.filter { it.state === Lesson.State.PLAYBACK }
                activity!!.showResult(filter)
     ```

16. 循环(27:00 ~)
    - repeat(数字): Test.kt
        ```
            //输出 0-29
            repeat(30){
                    println(it)
                }
        ```
    - for(i in a..b){}
        ```
            //输出 0-30
            for (i in 0..30){
                println(i)
            }
        ```
    - util: 左闭右开
        ```
            //遍历数组
            val pi = arrayOf(3, 1, 4, 1, 5, 9, 2, 6)

            for (i in 0 until pi.size){
                println(pi[i])
            }
        ```
17. 函数嵌套(31:30 ~)
    - MainActivity : 可将 verify() 放在 login() 中定义
    - 每次被调用会产生一个额外对象
    - 不建议使用

18. (34:00 ~)
    - BaseApplication
    - 去掉 companion object{} 中的
        ```
            fun currentApplication():Context{
                return currentApplication
            }
        ```
    - 在成员变量后面增加
        ```
            private set
        ```
    - 成员变量定义
        ```
            //java 中调用1
            lateinit var currentApplication:Context
                    private set

            //java 中调用2
            @JvmStatic
            lateinit var currentApplication:Context
                    private set

            //java 中调用3
            @JvmStatic
            @get:JvmName("myApp")
            lateinit var currentApplication:Context
                    private set
        ```
        - Java 中调用
            1. BaseApplication.Companion.getCurrentApplication();
            2. BaseApplication.getCurrentApplication();
            3. BaseApplication.myApp();

19. 类型推断简化函数声明(36:40 ~)
    - CacheUitls
        1. 函数体就一行代码,简化
            ```
                //before
                fun get(key:String):String?{
                    return SP.getString(key,null)
                }

                //after
                fun get(key:String):String? = SP.getString(key,null)
                fun get(key:String) = SP.getString(key,null) //进一步简化
            ```
20. 函数参数默认值 简化函数(38:00 ~)
    - Utils
    - 简化
        ```
            //before
             fun toast(msg: String) {
                toast(msg, Toast.LENGTH_SHORT)
            }

            fun toast(msg: String, duration: Int) {
                Toast.makeText(BaseApplication.currentApplication, msg, duration)
            }

            //after
            fun toast(msg: String, duration: Int = Toast.LENGTH_SHORT) {
                Toast.makeText(BaseApplication.currentApplication, msg, duration)
            }
        ```
    - CodeView
    - 简化
        ```
            //before
            class CodeView constructor(context: Context,attrs:AttributeSet?) :AppCompatEditText(context,attrs){
                constructor(context:Context):this(context,null)
            }

            //after
            class CodeView constructor(context: Context,attrs:AttributeSet? = null) :AppCompatEditText(context,attrs){

            }
        ```
    - Java 中调用,简化的函数
        - 要在方法上面加上注解:  @JvmOverloads
        - 如果时主构造方法,在 constructor 前加上注解

21. 扩展函数(41:10 ~), 这个很牛叉

    - 扩展函数在编译的时候就已经确定了,在 Java 中相当于静态
    - Utils 的 dp2px() 方法
        ```
            //before
            fun dp2px(dp: Float): Float {
                return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, displayMetrics)
            }
            //CodeView init{ ... } 中调用
            paint.strokeWidth = dp2px(6f)

            //after
            fun Float.dp2px(): Float {
                return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, displayMetrics)
            }
            //CodeView init{ ... } 中调用
            paint.strokeWidth = 6f.dp2px()
        ```

    - 如果扩展函数名和原有的函数名相同,则调用的时原来自有的函数
    - 两个扩展函数有父子关系(44:00 ~)
        ```
            //在 MainActivity

        ```
22. 扩展属性(46:40 ~)
    - 给类扩展成员属性
    - MainActivity val ViewGroup.firstChildren
        ```
            (window.decorView as ViewGroup).firstChildren
        ```

23. inline(48:00 ~)
    - 内联函数: 放在函数声明 fun 之前
    - 调用内联函数时,直接把 内联函数的函数体内容复制过去
    - 节省调用栈
    - 增加编译时间
    - 当传入类型为函数类型时,用比较好

24. 函数类型(54:00 ~)
    - Test.kt -> main() -> 函数类型
    - 不太明白

25. 抽象属性
    - BaseView
        ```
            //before
            fun getPresenter():T

            //after
            val presenter:T
        ```
    - 回到 LessonActivity,实现接口的方法


26. 委托(1:04:40 ~) ->  by lazy. 不明白
    - LessonActivity
        ```
            //before
            private val lessonPresenter = LessonPresenter(this)
            override fun getPresenter(): LessonPresenter {
            return lessonPresenter

            //after
            override val presenter: LessonPresenter? by lazy {
                LessonPresenter(this)
            }
        ```
    - by lazy { ... } 效果
        - { ... } 内只会被执行一次
        - 在访问 presenter 变量的时候,才会执行 { ... }

---

下面时作用域操作符

27. apply{ ... } (1:14:00)
    - CodeView paint
        ```
            //before
            var paint:Paint = Paint()

             init {
                    ...
                    paint.isAntiAlias = true
                    paint.style = Paint.Style.STROKE
                    paint.color = getContext().getColor(R.color.colorAccent)
                    paint.strokeWidth = 6f.dp2px()
                    ...
                }

             //after
             var paint:Paint = Paint().apply {
                 isAntiAlias = true
                 style = Paint.Style.STROKE
                 color = getContext().getColor(R.color.colorAccent)
                 strokeWidth = 6f.dp2px()
             }

             init {
                ...
             }

        ```
28. let{ ... } (1:16:00 ~)
    - LessonAdapter 内部类 LessonViewHolder_onBind() 方法里
        - if (state != null) { ... } 之前, 替换:
            ```
                //before
                if (state != null) {
                    setText(R.id.tv_state, state.stateName()!!)
                    var colorRes = R.color.playback
                    colorRes = when (state) {
                        Lesson.State.PLAYBACK -> {

                            // 即使在 {} 中也是需要 break 的。
                            R.color.playback
                        }
                        Lesson.State.LIVE -> R.color.live
                        Lesson.State.WAIT -> R.color.wait
                    }
                    val backgroundColor = itemView.context.getColor(colorRes)
                    getView<View>(R.id.tv_state)?.setBackgroundColor(backgroundColor)
                }

                //after
                lesson.state?.let {
                    setText(R.id.tv_state, it?.stateName()!!)
                    var colorRes = R.color.playback
                    colorRes = when (it) {
                        Lesson.State.PLAYBACK -> {

                            // 即使在 {} 中也是需要 break 的。
                            R.color.playback
                        }
                        Lesson.State.LIVE -> R.color.live
                        Lesson.State.WAIT -> R.color.wait
                    }
                    val backgroundColor = itemView.context.getColor(colorRes)
                    getView<View>(R.id.tv_state)?.setBackgroundColor(backgroundColor)
                }
            ```
    - also, run 也能替换 lef, 替换后 { ... } 有少许不同

29. run (1:19:00 ~), 简化代码
    - LessonActivity
        ```
            //before
             val recyclerView = findViewById<RecyclerView>(R.id.list)
            recyclerView.layoutManager = LinearLayoutManager(this)
            recyclerView.adapter = lessonAdapter
            recyclerView.addItemDecoration(DividerItemDecoration(this, LinearLayout.VERTICAL))

            //after
            findViewById<RecyclerView>(R.id.list).run {
                layoutManager = LinearLayoutManager(this@LessonActivity)
                adapter = lessonAdapter
                addItemDecoration(DividerItemDecoration(this@LessonActivity, LinearLayout.VERTICAL))
            }
        ```