Kotlin学习笔记

1.Kotlin文档,

  • 官方文档
  • Google官方说Kotlin First,
  • 中文博客,
  • 练习网站,
  • 入坑 Kotlin 开发前,这些项目能让你少走弯路
  • Kotlin 条件控制

2.kotlin使用Dagger2

  • Kotlin中使用Dagger2 可能导致错误"Dagger does not support injection into private fields"
    https://blog.csdn.net/xuhanbing/article/details/76212338
  • 如果是新项目,建议使用koin进行注入

3.java中调用Kotion写的控件失败

原因:没有引入kotlin相关插件
解决:首先在Projectbuild.gradle中的dependencies加入 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.21",然后在Modulebuild.gradle中引入插件plugins { id 'com.android.application' id 'kotlin-android' }

4.不要再使用Kotlin Extensions Gradle插件,推荐使用ViewDatabind

优雅地封装和使用 ViewBinding

5.插件

名称 描述
JsonToKotlinClass Json数据格式化Kotlin的插件
BugKotlinDocument-Github 输入/**就出来注释

Android Studio离线安装插件plugins

6.创建一个Handler

    private  var mHandler = Handler(Looper.getMainLooper()) {
        false
    }

注意1:要在内部使用mHandler.sendEmptyMessage(0),可以通过msg.target得到mHandler对象后发送
注意2:mainLooper可能为空,你要确定你是在主线程调用此mHandler,否则推荐使用Looper.getMainLooper()

7.适用于Kotlin的依赖注入框架Koin,用于替代Dragger2

koin-Github
适用于Kotlin的超好用依赖注入框架

8.库

说明 引入路径
生命周期-数据绑定ViewModel 官网ViewModelimplementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
协程 官网协程简介 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
依赖注入框架 koin,适用于Kotlin中替代Dragger,博客介绍Koin
数据存储 MMKV参考:SharedPreferences替换:MMKV集成与原理,一文读懂 SharedPreferences 的缺陷及一点点思考
图片加载 coil用kotlin写的图片加载库,可替代Glide

9.DSL篇

Kotlin之美——DSL篇

10.网络

使用协程,让网络世界更加美好
Retrofit + Kotlin请求接口时,遇到问题:Parameter type must not include a type variable or wildcard
使用Moshi更好地兼容Kotlin空安全

11.协程

kotlin coroutines guide-官方文档
Kotlin 协程-掘金博客
Kotlin Coroutines(协程)讲解
Kotlin Jetpack 实战:图解协程原理

  • Flow
    深入学习Kotlin之Flow(一),什么是Flow?Flow的基本使用
    Kotlin官方文档flow异步流
    官方推荐 Flow 取代 LiveData,有必要吗?
    理解协程、LiveData 和 Flow
    Android app中这样用flow更方便-加载列表数据
    实战 | 使用 Kotlin Flow 构建数据流 "管道"
    从 LiveData 迁移到 Kotlin 数据流

12.如何使用kapt

apply plugin: 'kotlin-kapt'
kapt {
generateStubs = true
}
kapt 'androidx.room:room-compiler:2.2.3'

注意:annotationProcessorkapt不能共存,如果你是javaKotlin混用的项目,那么使用了kapt后,其他的使用annotationProcessor也要改为kapt,不然构建项目就会报报错(我就是因为这个原因,搞了一天)

13.KTX扩展项

官方KTX介绍

14.泛型

我的Kotlin 学习之路(七)Kotlin之泛型、泛型约束、协变(Variance)

15.扩展函数

inline、noinline、crossinline傻傻分不清楚

16.序列化parcelize

首先引入插件

apply plugin: 'kotlin-parcelize'

然后,需要序列化的类:

import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
class UserBean(val name:String,val id:Int):Parcelable

17.单例模式

Kotlin中带参的单例模式

18.Java 中的写法在Kotlin 中是怎么写的?

Java 中的写法在Kotlin 中是怎么写的?

19.Kotlin for循环的几种使用方法

Kotlin for循环的几种使用方法

20.Jetpack Compose

Jetpack Compose Beta 版现已发布!-掘金翻译的官方文档
Jetpack Compose 环境基础,编写示例

21.数据存储

当前最好用的用于替代SharedPreferences的存储是MMKV,由于MMKV存储对象必须是实现了Parcelable的对象,而如果你还保留了大量java代码写的只实现了Serializable接口的对象。可用用如下方式读写:

/**
         * desc:保存对象
         * @param key
         * @param obj
         * @remind 要保存的对象,只能保存实现了serializable的对象
         */
        @JvmStatic
        fun saveObject(key: String?, obj: Serializable?) {
            try {
                //先将序列化结果写到byte缓存中,其实就分配一个内存空间
                val bos = ByteArrayOutputStream()
                val os = ObjectOutputStream(bos)
                //将对象序列化写入byte缓存
                os.writeObject(obj)
                //将序列化的数据转为16进制保存
                val bytesToHexString = bytesToHexString(bos.toByteArray())
                //保存该16进制数组
                mmkv.putString(key, bytesToHexString)
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
        @JvmStatic
        fun  readObject(key: String?): T? {
            val string = mmkv.getString(key, "")
            string?.let {
                //将16进制的数据转为数组,准备反序列化
                return try {
                    val stringToBytes = StringToBytes(string)
                    val bis = ByteArrayInputStream(stringToBytes)
                    val ois = ObjectInputStream(bis)
                    //返回反序列化得到的对象
                    ois.readObject() as T
                } catch (e: Exception) {
                    null
                }
            }
            return null
        }

        /**
         * desc:将数组转为16进制
         * @param bArray
         * @return modified:
         */
        private fun bytesToHexString(bArray: ByteArray?): String? {
            if (bArray == null) return null
            if (bArray.isEmpty()) return ""

            val sb = StringBuffer(bArray.size)
            var sTemp: String
            for (i in bArray.indices) {
                sTemp = Integer.toHexString(0xFF and bArray[i].toInt())
                if (sTemp.length < 2) sb.append(0)
                sb.append(sTemp.toUpperCase(Locale.getDefault()))
            }
            return sb.toString()
        }

        /**
         * 把16进制字符串转换成字节数组 @param hex @return
         */
        private fun StringToBytes(hex: String): ByteArray {
            val len = hex.length / 2
            val result = ByteArray(len)
            val achar = hex.toCharArray()
            for (i in 0 until len) {
                val pos = i * 2
                val toBe1 = toByte(achar[pos])
                val a = toBe1 shl 4
                val b = toByte(achar[pos + 1])
                result[i] = ((a or b).toByte())
            }
            return result
        }

        private fun toByte(c: Char): Int {
            return "0123456789ABCDEF".indexOf(c)
        }

但建议还是把对象改为实现Parcelable,因为Parcelable的效率是Serializable的10多倍。
而且用kotlin实现也很方便,参考上面16

22.坑

1.如果要使用@BindingAdapter对数据进行绑定,那么需要添加@JvmStatic注释,否则报错

    //普通网络图片
    @JvmStatic
    @BindingAdapter("url")
    fun bindUrl(view: ImageView, imageUrl: String?) {
        Glide.with(view).load(imageUrl).into(view)
    }

2.java一键转kotlin后会出现很多!!标记的内容,使用了!!的字段要非常确定不为空null
解决方案:让你的 Kotlin 代码远离 !!

3.友盟统计SDK不支持kotlin,以前是java的时候有数据,改为kotlin的一周,发现没有统计数据了
解决:MyApplication改用java代码编写,然后在里面做友盟的初始化操作
4.高德地图黑屏:神奇的bug
最开始以为是kotlin的问题,用了java写页面,问题依旧,最后发现三个条件导致页面黑屏,a.文本数据设置中包含了特殊字符:()或· b.使用了高德地图mapView.onCreate(savedInstanceState),c.红米k30手机(目前测试其他手机正常)

  • 单独使用地图,没有问题(说明高德没有)
  • 单独对文本设置包含了特殊字符的文本没有问题(说明可以设置特殊字符的文本:重庆市渝中区菜袁路渝中区旭庆·江湾国际花都(菜袁路西))
  • 不使用红米手机K30,设置了地图也设置了包含了特殊字符的文本也没问题
    最终结论:手机有问题

解决方案一:去掉特殊文本中的特殊字符:重庆市渝中区菜袁路渝中区旭庆江湾国际花都菜袁路西(不合理,显示的内容缺少)
解决方案二:不使用红米手机(测试不干)
解决方案三:猜想黑屏是渲染导致,那么可以延迟处理其中一方,地图因为要跟随onCreate的创建而绑定,没法弄,于是考虑延迟300豪秒来设置特殊文本到文本控件中

23.关键字

Kotlin系列之let、with、run、apply、also函数的使用

字段 用法 说明
also object.also{//todo} also函数返回的则是传入对象的本身,和let函数使用类似

24.MVVM记录关键点

  • ViewModel
    ViewModel-Google官网
    ViewModel
    【背上Jetpack之ViewModel】即使您不使用MVVM也要了解ViewModel ——ViewModel 的职能边界
  • LivewData
    LiveData数据改变时通知相应的界面代码进行更新

1.要绑定每次数据的更新,需要如下代码

binding.setLifecycleOwner(this)//关键代码:绑定每次LiveData数据的更新

2.如果想多个页面使用观察同一个数据,可以设置此数据为静态变量

companion object{
        private var userData = MutableLiveData()
    }

25.代码混淆

Android 代码混淆,到底做了什么?

26.zxing二维码扫描

zxing-android-embedded

27.RecyclerView 配合 DiffUtil,好用到飞起

https://www.cnblogs.com/plokmju/p/7385136.html

28.Fragment的添加,删除,替换,https://cloud.tencent.com/developer/article/1036708

29.在Kotlin中对空字段的处理

val submitTime:String=""
get() = if(TextUtils.isEmpty(field))"--" else TimeUtils.ymdhmsToYmdhm(field)

30.kotlin 字符串_10个有用的Kotlin字符串扩展

https://blog.csdn.net/weixin_26727575/article/details/108497391

31.AS编译报错:More than one file was found with OS independent path META-INF/library_release.kotlin_module

https://blog.csdn.net/jabony/article/details/112930562

32.kotlin - 实现静态单例的方式

https://www.jianshu.com/p/fe44743d0f01

33.hook:无所不能的 hook,让应用不再崩溃

https://mp.weixin.qq.com/s/6IgiJQEWUvfzxfP1gJFVLQ
https://github.com/eleme/lancet

34.构建异常:

引入最新ExoPlayer:The minCompileSdk (31) specified in adependency's AAR metadata (META-INF/com/android/build/gradle/aar-metadata.properties)is greater than this module's compileSdkVersion (android-30).Dependency: androidx.core:core:1.7.0.
解决一:https://www.cjavapy.com/article/2241/【无效】
解决二:我是因为引入了implementation 'com.google.android.exoplayer:exoplayer:2.16.1'去掉后即可

修改buildToolsVersion '31.0.0'后报错,Installed Build Tools revision 31.0.0 is corrupted. Remove and install again
解决:https://blog.n0ts.cn/1435.html

修改compileSdkVersion 31和 targetSdkVersion 31报错:> Manifest merger failed : Apps targeting Android 12 and higher are required to specify an explicit value forandroid:exportedwhen the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.
解决: 给有过滤器的页面添加android:exported属性

添加:android:exported="true"后依然报错
解决:

异常:The minCompileSdk (31) specified in adependency's AAR metadata (META-INF/com/android/build/gradle/aar-metadata.properties)
配置冲突:https://www.cjavapy.com/article/2241/

35.自定义View-第十四步:setShadowLayer阴影与SetMaskFilter发光效果

https://www.jianshu.com/p/2f1024f9c554

36.过时的OnActivityResult替代品registerForActivityResult

https://www.jianshu.com/p/b6798dcf090a
ActivityResultContract抽象类
ActivityResultCallback接口回调
ActivityResultRegistry抽象类

    @NonNull
    @Override
    public final  ActivityResultLauncher registerForActivityResult(
            @NonNull ActivityResultContract contract,
            @NonNull ActivityResultCallback callback) {
        return registerForActivityResult(contract, mActivityResultRegistry, callback);
    }
    @NonNull
    @Override
    public final  ActivityResultLauncher registerForActivityResult(
            @NonNull final ActivityResultContract contract,
            @NonNull final ActivityResultRegistry registry,
            @NonNull final ActivityResultCallback callback) {
        return registry.register(
                "activity_rq#" + mNextLocalRequestCode.getAndIncrement(), this, contract, callback);
    }

你可能感兴趣的:(Kotlin学习笔记)