背景
最近我們?cè)谧鰠^(qū)塊鏈相關(guān)的錢包項(xiàng)目淋叶,新的App使用全新的技術(shù)棧。在Android中我們使用Kotlin+RxJava+Android Architecture Components昙衅,在iOS中使用Swift+RxSwift。本文不討論App的架構(gòu)定鸟,只討論項(xiàng)目中所使用到的Kotlin的特性而涉。
在Android的App中,可以毫不夸張地說(shuō)联予,我們95%以上的代碼使用了Kotlin開發(fā)的啼县。由此,很有必要對(duì)這一階段使用Kotlin做一個(gè)簡(jiǎn)單的小結(jié)沸久。
使用的Kotlin特性:
一.擴(kuò)展函數(shù)
Kotlin允許開發(fā)者在不改變已有類的情況下季眷,為某個(gè)類添加新的函數(shù)。這個(gè)特性叫做擴(kuò)展函數(shù)卷胯。
舉一個(gè)簡(jiǎn)單的例子子刮。如果要關(guān)閉一個(gè)I/O流,使用Java可能是寫一個(gè)工具方法窑睁。
/**
* 安全關(guān)閉io流
* @param closeable
*/
public static void closeQuietly(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
對(duì)Kotlin而言挺峡,可以對(duì)Closeable擴(kuò)展一個(gè)函數(shù)closeQuietly()。
fun Closeable?.closeQuietly() {
try {
this?.close()
} catch (e: Throwable) {
}
}
之后担钮,任何實(shí)現(xiàn)了Closeable接口的類橱赠,都可以使用它本身的closeQuietly()方法來(lái)關(guān)閉流。我們不再需要那個(gè)工具方法了箫津。
在項(xiàng)目中狭姨,我們使用擴(kuò)展函數(shù)對(duì)Glide做了封裝,大大簡(jiǎn)化了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)
除此之外送挑,我們還很多地方都用到了擴(kuò)展函數(shù)。
我順便更新了我的Kolin的工具類庫(kù)暖眼,它包括各種utils和各種extension
https://github.com/fengzhizi715/SAF-Kotlin-Utils
二.尾隨閉包
一開始我并不了解這個(gè)概念惕耕。偶然間我看到我們的小伙伴在使用RxBus時(shí),寫下了這樣的代碼:
RxBus.get().register(LogoutEvent::class.java) { refresh() }
當(dāng)時(shí)我感覺很疑惑诫肠,因?yàn)镽xBus是我寫的司澎,記得沒有提供這樣的方法啊。點(diǎn)擊register()方法進(jìn)去看之后栋豫,發(fā)現(xiàn)register是這樣的:
public <T> Disposable register(Class<T> eventType, Consumer<T> onNext) {
return toObservable(eventType).observeOn(AndroidSchedulers.mainThread()).subscribe(onNext);
}
由于使用了Kotlin挤安,該register方法的使用可以簡(jiǎn)化成這樣:
RxBus.get().register(LogoutEvent::class.java,{
refresh()
})
由于register()最后一個(gè)參數(shù)是一個(gè)方法或者說(shuō)是一個(gè)閉包,可以把方法或者閉包提到最外面丧鸯。變成項(xiàng)目中看到的樣子:
RxBus.get().register(LogoutEvent::class.java) { refresh() }
這就是尾隨閉包蛤铜,可以讓代碼看起來(lái)更加簡(jiǎn)潔。
三.with的用法
with是將某個(gè)對(duì)象作為函數(shù)的參數(shù),在函數(shù)塊內(nèi)可以通過(guò) this 指代該對(duì)象围肥。在函數(shù)塊內(nèi)可以直接調(diào)用對(duì)象的方法或者屬性剿干。
/**
* Calls the specified function [block] with the given [receiver] as its receiver and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
在使用with之前的某個(gè)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之后,該函數(shù)塊可以省略"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)
}
}
}
四.其他
這部分的內(nèi)容并不是Kotlin的特性穆刻,是我使用Kotlin開發(fā)的工具置尔。比如日志框架L以及Retrofit的日志攔截器。這些庫(kù)氢伟,其實(shí)很早就開發(fā)了榜轿,最近稍微升級(jí)了一下功能。
L的github地址:
https://github.com/fengzhizi715/SAF-Kotlin-log
Retrofit日志攔截器的github地址:
https://github.com/fengzhizi715/saf-logginginterceptor
日志攔截器的效果圖:
總結(jié)
Kotlin吸收了多種語(yǔ)言的優(yōu)點(diǎn)朵锣,相對(duì)于Java有很多激動(dòng)人心的特性谬盐,極大地提高了開發(fā)效率。本文介紹的特性也只是滄海一粟诚些。接下來(lái)设褐,我會(huì)整理更多項(xiàng)目中所使用的Kotlin特性。
BTW泣刹,我在寫這篇文章的時(shí)候國(guó)內(nèi)第一個(gè)錢包版本剛剛做完,開始第一輪測(cè)試犀被。
該系列的相關(guān)文章:
使用Kotlin高效地開發(fā)Android App(五)完結(jié)篇
使用Kotlin高效地開發(fā)Android App(四)
使用Kotlin高效地開發(fā)Android App(三)
使用Kotlin高效地開發(fā)Android App(二)