使用Kotlin高效地開發Android App(一)

Tony沈哲發表於2018-04-24
星戰小兵.jpg

背景

最近我們在做區塊鏈相關的錢包專案,新的App使用全新的技術棧。在Android中我們使用Kotlin+RxJava+Android Architecture Components,在iOS中使用Swift+RxSwift。本文不討論App的架構,只討論專案中所使用到的Kotlin的特性。

在Android的App中,可以毫不誇張地說,我們95%以上的程式碼使用了Kotlin開發的。由此,很有必要對這一階段使用Kotlin做一個簡單的小結。

使用的Kotlin特性:

一.擴充套件函式

Kotlin允許開發者在不改變已有類的情況下,為某個類新增新的函式。這個特性叫做擴充套件函式。

舉一個簡單的例子。如果要關閉一個I/O流,使用Java可能是寫一個工具方法。

    /**     * 安全關閉io流     * @param closeable     */    public static void closeQuietly(Closeable closeable) { 
if (closeable != null) {
try {
closeable.close();

} catch (IOException e) {
e.printStackTrace();

}
}
}複製程式碼

對Kotlin而言,可以對Closeable擴充套件一個函式closeQuietly()。

fun Closeable?.closeQuietly() { 
try {
this?.close()
} catch (e: Throwable) {

}
}複製程式碼

之後,任何實現了Closeable介面的類,都可以使用它本身的closeQuietly()方法來關閉流。我們不再需要那個工具方法了。

在專案中,我們使用擴充套件函式對Glide做了封裝,大大簡化了Glide的使用。

/** * 佔位符矩形 */fun ImageView.load(url: String) { 
get(url).placeholder(R.drawable.shape_default_rec_bg) .error(R.drawable.shape_default_rec_bg) .into(this)
}/** * 佔位符圓角矩形 */fun ImageView.loadRound(url: String) {
get(url).placeholder(R.drawable.shape_default_round_bg) .error(R.drawable.shape_default_round_bg)// .apply(RequestOptions.bitmapTransform(RoundedCornersTransformation(DisplayUtil.dp2px(context, 6f), 0))) .transform(RoundedCornersTransformation(DisplayUtil.dp2px(context, 6f), 0)) .into(this)
}/** * 佔位符圓形 */fun ImageView.loadCircle(url: Drawable) {
get(url).placeholder(R.drawable.shape_default_circle_bg) .error(R.drawable.shape_default_circle_bg) .into(this)
}fun ImageView.loadCircle(url: String) {
get(url).placeholder(R.drawable.shape_default_circle_bg) .error(R.drawable.shape_default_circle_bg) .into(this)
}fun ImageView.get(url: String): GlideRequest<
Drawable>
= GlideApp.with(context).load(url)fun ImageView.get(url: Drawable): GlideRequest<
Drawable>
= GlideApp.with(context).load(url)複製程式碼

除此之外,我們還很多地方都用到了擴充套件函式。

我順便更新了我的Kolin的工具類庫,它包括各種utils和各種extensionhttps://github.com/fengzhizi715/SAF-Kotlin-Utils

二.尾隨閉包

一開始我並不瞭解這個概念。偶然間我看到我們的小夥伴在使用RxBus時,寫下了這樣的程式碼:

RxBus.get().register(LogoutEvent::class.java) { 
refresh()
}複製程式碼

當時我感覺很疑惑,因為RxBus是我寫的,記得沒有提供這樣的方法啊。點選register()方法進去看之後,發現register是這樣的:

    public <
T>
Disposable register(Class<
T>
eventType, Consumer<
T>
onNext) {
return toObservable(eventType).observeOn(AndroidSchedulers.mainThread()).subscribe(onNext);

}複製程式碼

由於使用了Kotlin,該register方法的使用可以簡化成這樣:

RxBus.get().register(LogoutEvent::class.java,{            refresh()        
})複製程式碼

由於register()最後一個引數是一個方法或者說是一個閉包,可以把方法或者閉包提到最外面。變成專案中看到的樣子:

RxBus.get().register(LogoutEvent::class.java) { 
refresh()
}複製程式碼

這就是尾隨閉包,可以讓程式碼看起來更加簡潔。

三.with的用法

with是將某個物件作為函式的引數,在函式塊內可以通過 this 指代該物件。在函式塊內可以直接呼叫物件的方法或者屬性。

/** * Calls the specified function [block] with the given [receiver] as its receiver and returns its result. */@kotlin.internal.InlineOnlypublic inline fun <
T, R>
with(receiver: T, block: T.()
->
R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
} return receiver.block()
}複製程式碼

在使用with之前的某個Adapter

class AppPublisherAdapter : BaseAdapter<
BoundAppInfoResponse.AppInfo>
() {
override fun getLayoutId(viewType: Int): Int = R.layout.cell_app_publisher override fun onBindViewHolderImpl(holder: BaseViewHolder, position: Int,content: BoundAppInfoResponse.AppInfo) {
holder.itemView.tv_game_name.text = content.name if (content.is_bound) {
holder.itemView.tv_bound_user_name.text = content.bound_user_name holder.itemView.tv_bound_user_name.setTextColor(context.resources.getColor(R.color.color_bound_user_name))
} else {
holder.itemView.tv_bound_user_name.text = context.getString(R.string.bind_on_account) holder.itemView.tv_bound_user_name.setTextColor(context.resources.getColor(R.color.color_bind_on_account))
} holder.itemView.iv_game_icon.load(content.logo_url)
}
}複製程式碼

使用with之後,該函式塊可以省略”content.”

class AppPublisherAdapter : BaseAdapter<
BoundAppInfoResponse.AppInfo>
() {
override fun getLayoutId(viewType: Int): Int = R.layout.cell_app_publisher override fun onBindViewHolderImpl(holder: BaseViewHolder, position: Int, content: BoundAppInfoResponse.AppInfo) {
with(content) {
holder.itemView.tv_game_name.text = name if (is_bound) {
holder.itemView.tv_bound_user_name.text = bound_user_name holder.itemView.tv_bound_user_name.setTextColor(context.color(R.color.color_bound_user_name))
} else {
holder.itemView.tv_bound_user_name.text = context.string(R.string.bind_on_account) holder.itemView.tv_bound_user_name.setTextColor(context.color(R.color.color_bind_on_account))
} holder.itemView.iv_game_icon.load(logo_url)
}
}
}複製程式碼

四.其他

這部分的內容並不是Kotlin的特性,是我使用Kotlin開發的工具。比如日誌框架L以及Retrofit的日誌攔截器。這些庫,其實很早就開發了,最近稍微升級了一下功能。

L的github地址:https://github.com/fengzhizi715/SAF-Kotlin-log

Retrofit日誌攔截器的github地址:https://github.com/fengzhizi715/saf-logginginterceptor

日誌攔截器的效果圖:

request的效果圖.jpeg
response的效果圖.jpeg

總結

Kotlin吸收了多種語言的優點,相對於Java有很多激動人心的特性,極大地提高了開發效率。本文介紹的特性也只是滄海一粟。接下來,我會整理更多專案中所使用的Kotlin特性。

BTW,我在寫這篇文章的時候國內第一個錢包版本剛剛做完,開始第一輪測試。

該系列的相關文章:

使用Kotlin高效地開發Android App(五)完結篇

使用Kotlin高效地開發Android App(四)

使用Kotlin高效地開發Android App(三)

使用Kotlin高效地開發Android App(二)


Java與Android技術棧:每週更新推送原創技術文章,歡迎掃描下方的公眾號二維碼並關注,期待與您的共同成長和進步。

使用Kotlin高效地開發Android App(一)

來源:https://juejin.im/post/5ade9ce3f265da0b80705e22

相關文章