鼓勵使用Kotlin, 鼓勵使用新特性脊串, 提倡Kotlin嚴(yán)格Review
代碼規(guī)約 Coding Conventions
https://kotlinlang.org/docs/reference/coding-conventions.html
代碼樣例 kotlin Idiomatic
https://kotlinlang.org/docs/reference/idioms.html
Github中搜一下 kotlin Idiomatic 試試照雁?
可能遇到的比較大的坑
代碼規(guī)范 or Bad Case【持續(xù)添加】
- 判空
nullable?.let{
//非空操作
}
//涉及bool
if(nullable?.isTrue == true) {
}
- evils 的作用范圍
val value = if(matches()) nullable :? 1 else nullable ?:2
val value = (if (matches()) nullable1 else nullable2) ?: 0
- 拒絕強制非空
//禁止出現(xiàn)!!強制非空操作
var value = InstanceManager.getInstance()!!.value
- 合理使用 run,let,with,apply 等
// Java 風(fēng)格
fun trackFeedItemRemoved(concernId: Long, groupId: Long) {
val params = JSONObject()
params.putOpt("concern_id", concernId)
params.putOpt("group_id", groupId)
AppLogNewUtils.onEventV3("concern_topic_article_remove", params)
}
// 使用Apply
fun trackDescriptionRichContentClick(concernId: Long, text: String?) {
Bundle().apply {
putLong("concern_id", concernId)
putString("text", text)
}.let {//可以用run或者apply嗎抒倚? 邏輯上可以用览露,單從代碼語義上不建議**
AppLogNewUtils.onEventV3Bundle("ugc_topic_click", **it**)
}
}
- 單例
`// Object生成的是線程安全的餓漢式單例`
`// Lazy 實現(xiàn)線程安全的懶漢式單例`
`class SingletonDemo private constructor() { `
`companion object {`
`val instance: SingletonDemo by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {`
` SingletonDemo() `
` } `
` } `
`}`
- kotlin可以省略Builder模式
`// Java Builder 風(fēng)格的例子`
`val builder = PreLayoutTextViewConfig.builder()`
` .textViewWidth(PostTextLayoutProvider.INSTANCE.getWidthInPixel())`
` .textSize(PostTextLayoutProvider.INSTANCE.getTextSizeInPixel().toInt())`
` .textContent(content)`
` .textRichContentStr(commentBase.content_rich_span)`
` .ellipsizeContent(TTRichTextViewConfig.*ELLIPSIZE_ALL*)`
` .ellipsizeClickLength(2)`
` .maxLineCount(maxLine)`
` .defaultLineCount(defaultLine)`
`val interceptor = PostSpanInterceptor()`
`interceptor.cellRef = postCell`
`builder.interceptor(interceptor)`
`return builder.build()`
`//直接kotlin 可以省略build`
`//如果有需要從Java中調(diào)用還得寫B(tài)uidler模式...`
`val dataSource = BasicDataSource().apply **{**`
`driverClassName = "com.mysql.jdbc.Driver"`
`url = "jdbc:mysql://domain:3309/db"`
`username = "username"`
`password = "password"`
`maxTotal = 40`
`maxIdle = 40`
`minIdle = 4`
`**}**`
- 代碼可讀性
`// 隨便寫的一些代碼`
`// 用了很多kotlin函數(shù)省略了一些臨時變量被丧,看上去很高端乱顾,但是代碼的可讀性很差`
`fun test(context: Context) {`
`*with*(View.inflate(context, R.layout.*abc*, null) as ViewGroup) **{**`
`*repeat*(*childCount*) **{**`
`*with*(getChildAt(**it**) as Button) **{**`
`*apply* **{**`
`*text* = "button$**it**"`
`setOnClickListener **{**`
`*takeIf* **{ it** == getChildAt(0) **}**?.*run* **{**`
`doClickTopButton()`
`**}**?.let **{**`
`doClickOthers()`
`**}**`
`** }**`
`** }**`
`** }**`
`** }**`
`** }**`
`}`
- 不安全的類型轉(zhuǎn)換
`// findViewById 是nullable`
`val readCountTv: TextView = itemView.findViewById(R.id.*read_count*) as TextView`
`val readCountWrapper: LinearLayout = itemView.findViewById(R.id.*read_count_wrapper*) as LinearLayout`
- kotlin 調(diào)用 Java 時板祝, 屬性調(diào)用可能調(diào)用Java的get方法, 有些場景會有隱藏的坑
`override fun onBackPressed() {`
`//此處videoController 實際調(diào)用的是下面Java代碼的getVideoController()`
`//當(dāng)videoController 為空時走净,反而會去創(chuàng)建一個新的實例`
`if (videoController?.isFullScreen == true && videoController.onBackPressed(this)) {`
`return`
` }`
` finish()`
`}`
`@Override`
`public IFeedVideoController getVideoController() {`
if (mVideoController == null) {
mVideoController = createVideoController()
initVideoListener();
if (mVideoController != null) {
mVideoController.addListener(mIVideoFullscreen);
}
}
return mVideoController;
`}`
kotlin構(gòu)造函數(shù) AS中show kotlin bytecode decode生成的java和最終打包生成的class不一致
用kotlinc 編譯了下券时,目前看來是一致的
- kotlin中實現(xiàn)if (not) null
`//空和非空都有處理時,建議還是使用Java風(fēng)格的寫法 ?[kotlin if null 怎么寫更優(yōu)雅](https://bytedance.feishu.cn/docs/doccnlAPdp8LyMvHrVnYj9yRb5d)? `
`var variable :Any? = null `
`if(variable != null) {`
` doSomeThing()`
`} else {`
` doSomeThingElse()`
`}`
- SDK項目中減少使用data class
`//主要是因為data支持解構(gòu)伏伯,業(yè)務(wù)方如果是解構(gòu)的寫法橘洞,sdk升級時如果不全量編譯可能有問題`
`//參考 https://jakewharton.com/public-api-challenges-in-kotlin/`
- Kotlin編譯后的隱式import(Kotlin的bug?)说搅,這樣可能會導(dǎo)致增量編譯的包有問題
`//從字節(jié)碼看有IRelationStateCallback的依賴`
`//實際Kotlin代碼中不會存在對RelationStatusCallback的直接依賴`
`byte var8;`
`label16: {`
` IRelationDepend var10000 = (IRelationDepend)ServiceManager2.getService (IRelationDepend.class);`
` if (var10000 != null) {`
`if (var10000.userIsFollowing(userId, (RelationStatusCallback)null)) {`
`var8 = 1;`
` break label16;`
` }`
` }`
`var8 = 0;`
`}`