1.Kotlin文檔,
2.kotlin使用Dagger2
-
Kotlin中使用Dagger2可能導(dǎo)致錯誤"Dagger does not support injection into private fields"
https://blog.csdn.net/xuhanbing/article/details/76212338 - 如果是新項(xiàng)目,建議使用koin進(jìn)行注入
3.java中調(diào)用Kotion寫的控件失敗
原因:沒有引入kotlin相關(guān)插件
解決:首先在Project的build.gradle中的dependencies加入 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.21",然后在Module的build.gradle中引入插件plugins { id 'com.android.application' id 'kotlin-android' }
4.不要再使用Kotlin Extensions Gradle插件,推薦使用ViewDatabind
5.插件
| 名稱 | 描述 |
|---|---|
| JsonToKotlinClass | Json數(shù)據(jù)格式化Kotlin的插件 |
| BugKotlinDocument-Github | 輸入/**就出來注釋 |
6.創(chuàng)建一個(gè)Handler
private var mHandler = Handler(Looper.getMainLooper()) {
false
}
注意1:要在內(nèi)部使用mHandler.sendEmptyMessage(0),可以通過msg.target得到mHandler對象后發(fā)送
注意2:mainLooper可能為空,你要確定你是在主線程調(diào)用此mHandler,否則推薦使用Looper.getMainLooper()
7.適用于Kotlin的依賴注入框架Koin,用于替代Dragger2
koin-Github
適用于Kotlin的超好用依賴注入框架
8.庫
| 說明 | 引入路徑 |
|---|---|
生命周期-數(shù)據(jù)綁定ViewModel
|
官網(wǎng)ViewModelimplementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
|
| 協(xié)程 |
官網(wǎng)協(xié)程簡介 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
|
| 依賴注入框架 | koin,適用于Kotlin中替代Dragger,簡書博客介紹Koin |
| 數(shù)據(jù)存儲 | MMKV參考:SharedPreferences替換:MMKV集成與原理,一文讀懂 SharedPreferences 的缺陷及一點(diǎn)點(diǎn)思考 |
| 圖片加載 |
coil用kotlin寫的圖片加載庫,可替代Glide
|
9.DSL篇
10.網(wǎng)絡(luò)
使用協(xié)程,讓網(wǎng)絡(luò)世界更加美好
Retrofit + Kotlin請求接口時(shí),遇到問題:Parameter type must not include a type variable or wildcard
使用Moshi更好地兼容Kotlin空安全
11.協(xié)程
kotlin coroutines guide-官方文檔
Kotlin 協(xié)程-掘金博客
Kotlin Coroutines(協(xié)程)講解
Kotlin Jetpack 實(shí)戰(zhàn):圖解協(xié)程原理
- Flow
深入學(xué)習(xí)Kotlin之Flow(一),什么是Flow?Flow的基本使用
Kotlin官方文檔flow異步流
官方推薦 Flow 取代 LiveData,有必要嗎?
理解協(xié)程、LiveData 和 Flow
Android app中這樣用flow更方便-加載列表數(shù)據(jù)
實(shí)戰(zhàn) | 使用 Kotlin Flow 構(gòu)建數(shù)據(jù)流 "管道"
從 LiveData 遷移到 Kotlin 數(shù)據(jù)流
12.如何使用kapt
apply plugin: 'kotlin-kapt'
kapt {
generateStubs = true
}
kapt 'androidx.room:room-compiler:2.2.3'
注意:annotationProcessor和kapt不能共存,如果你是java和Kotlin混用的項(xiàng)目,那么使用了kapt后,其他的使用annotationProcessor也要改為kapt,不然構(gòu)建項(xiàng)目就會報(bào)報(bào)錯(我就是因?yàn)檫@個(gè)原因,搞了一天)
13.KTX擴(kuò)展項(xiàng)
14.泛型
我的Kotlin 學(xué)習(xí)之路(七)Kotlin之泛型、泛型約束、協(xié)變(Variance)
15.擴(kuò)展函數(shù)
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.單例模式
18.Java 中的寫法在Kotlin 中是怎么寫的?
19.Kotlin for循環(huán)的幾種使用方法
20.Jetpack Compose
Jetpack Compose Beta 版現(xiàn)已發(fā)布!-掘金翻譯的官方文檔
Jetpack Compose 環(huán)境基礎(chǔ),編寫示例
21.數(shù)據(jù)存儲
當(dāng)前最好用的用于替代SharedPreferences的存儲是MMKV,由于MMKV存儲對象必須是實(shí)現(xiàn)了Parcelable的對象,而如果你還保留了大量java代碼寫的只實(shí)現(xiàn)了Serializable接口的對象。可用用如下方式讀寫:
/**
* desc:保存對象
* @param key
* @param obj
* @remind 要保存的對象,只能保存實(shí)現(xiàn)了serializable的對象
*/
@JvmStatic
fun saveObject(key: String?, obj: Serializable?) {
try {
//先將序列化結(jié)果寫到byte緩存中,其實(shí)就分配一個(gè)內(nèi)存空間
val bos = ByteArrayOutputStream()
val os = ObjectOutputStream(bos)
//將對象序列化寫入byte緩存
os.writeObject(obj)
//將序列化的數(shù)據(jù)轉(zhuǎn)為16進(jìn)制保存
val bytesToHexString = bytesToHexString(bos.toByteArray())
//保存該16進(jìn)制數(shù)組
mmkv.putString(key, bytesToHexString)
} catch (e: IOException) {
e.printStackTrace()
}
}
@JvmStatic
fun <T : Any?> readObject(key: String?): T? {
val string = mmkv.getString(key, "")
string?.let {
//將16進(jìn)制的數(shù)據(jù)轉(zhuǎn)為數(shù)組,準(zhǔn)備反序列化
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:將數(shù)組轉(zhuǎn)為16進(jìn)制
* @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進(jìn)制字符串轉(zhuǎn)換成字節(jié)數(shù)組 @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)
}
但建議還是把對象改為實(shí)現(xiàn)Parcelable,因?yàn)?code>Parcelable的效率是Serializable的10多倍。
而且用kotlin實(shí)現(xiàn)也很方便,參考上面16
22.坑
1.如果要使用@BindingAdapter對數(shù)據(jù)進(jìn)行綁定,那么需要添加@JvmStatic注釋,否則報(bào)錯
//普通網(wǎng)絡(luò)圖片
@JvmStatic
@BindingAdapter("url")
fun bindUrl(view: ImageView, imageUrl: String?) {
Glide.with(view).load(imageUrl).into(view)
}
2.java一鍵轉(zhuǎn)kotlin后會出現(xiàn)很多!!標(biāo)記的內(nèi)容,使用了!!的字段要非常確定不為空null,
解決方案:讓你的 Kotlin 代碼遠(yuǎn)離 !!
3.友盟統(tǒng)計(jì)SDK不支持kotlin,以前是java的時(shí)候有數(shù)據(jù),改為kotlin的一周,發(fā)現(xiàn)沒有統(tǒng)計(jì)數(shù)據(jù)了
解決:MyApplication改用java代碼編寫,然后在里面做友盟的初始化操作
4.高德地圖黑屏:神奇的bug
最開始以為是kotlin的問題,用了java寫頁面,問題依舊,最后發(fā)現(xiàn)三個(gè)條件導(dǎo)致頁面黑屏,a.文本數(shù)據(jù)設(shè)置中包含了特殊字符:()或· b.使用了高德地圖mapView.onCreate(savedInstanceState),c.紅米k30手機(jī)(目前測試其他手機(jī)正常)
- 單獨(dú)使用地圖,沒有問題(說明高德沒有)
- 單獨(dú)對文本設(shè)置包含了特殊字符的文本沒有問題(說明可以設(shè)置特殊字符的文本:重慶市渝中區(qū)菜袁路渝中區(qū)旭慶·江灣國際花都(菜袁路西))
- 不使用紅米手機(jī)K30,設(shè)置了地圖也設(shè)置了包含了特殊字符的文本也沒問題
最終結(jié)論:手機(jī)有問題
解決方案一:去掉特殊文本中的特殊字符:重慶市渝中區(qū)菜袁路渝中區(qū)旭慶江灣國際花都菜袁路西(不合理,顯示的內(nèi)容缺少)
解決方案二:不使用紅米手機(jī)(測試不干)
解決方案三:猜想黑屏是渲染導(dǎo)致,那么可以延遲處理其中一方,地圖因?yàn)橐SonCreate的創(chuàng)建而綁定,沒法弄,于是考慮延遲300豪秒來設(shè)置特殊文本到文本控件中
23.關(guān)鍵字
Kotlin系列之let、with、run、apply、also函數(shù)的使用
| 字段 | 用法 | 說明 |
|---|---|---|
also |
object.also{//todo} |
also函數(shù)返回的則是傳入對象的本身,和let函數(shù)使用類似 |
24.MVVM記錄關(guān)鍵點(diǎn)
- ViewModel
ViewModel-Google官網(wǎng)
ViewModel簡書
【背上Jetpack之ViewModel】即使您不使用MVVM也要了解ViewModel ——ViewModel 的職能邊界 - LivewData
LiveData數(shù)據(jù)改變時(shí)通知相應(yīng)的界面代碼進(jìn)行更新
1.要綁定每次數(shù)據(jù)的更新,需要如下代碼
binding.setLifecycleOwner(this)//關(guān)鍵代碼:綁定每次LiveData數(shù)據(jù)的更新
2.如果想多個(gè)頁面使用觀察同一個(gè)數(shù)據(jù),可以設(shè)置此數(shù)據(jù)為靜態(tài)變量
companion object{
private var userData = MutableLiveData<User>()
}
25.代碼混淆
26.zxing二維碼掃描
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個(gè)有用的Kotlin字符串?dāng)U展
https://blog.csdn.net/weixin_26727575/article/details/108497391
31.AS編譯報(bào)錯: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 - 實(shí)現(xiàn)靜態(tài)單例的方式
http://www.itdecent.cn/p/fe44743d0f01
33.hook:無所不能的 hook,讓應(yīng)用不再崩潰
https://mp.weixin.qq.com/s/6IgiJQEWUvfzxfP1gJFVLQ
https://github.com/eleme/lancet
34.構(gòu)建異常:
引入最新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/【無效】
解決二:我是因?yàn)橐肓?code>implementation 'com.google.android.exoplayer:exoplayer:2.16.1'去掉后即可
修改buildToolsVersion '31.0.0'后報(bào)錯,Installed Build Tools revision 31.0.0 is corrupted. Remove and install again
解決:https://blog.n0ts.cn/1435.html
修改compileSdkVersion 31和 targetSdkVersion 31報(bào)錯:> 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"后依然報(bào)錯
解決:
異常: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發(fā)光效果
http://www.itdecent.cn/p/2f1024f9c554
36.過時(shí)的OnActivityResult替代品registerForActivityResult
http://www.itdecent.cn/p/b6798dcf090a
ActivityResultContract抽象類
ActivityResultCallback接口回調(diào)
ActivityResultRegistry抽象類
@NonNull
@Override
public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
@NonNull ActivityResultContract<I, O> contract,
@NonNull ActivityResultCallback<O> callback) {
return registerForActivityResult(contract, mActivityResultRegistry, callback);
}
@NonNull
@Override
public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
@NonNull final ActivityResultContract<I, O> contract,
@NonNull final ActivityResultRegistry registry,
@NonNull final ActivityResultCallback<O> callback) {
return registry.register(
"activity_rq#" + mNextLocalRequestCode.getAndIncrement(), this, contract, callback);
}