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

星戰小兵.jpg

背景

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

在Android的App中,能夠絕不誇張地說,咱們95%以上的代碼使用了Kotlin開發的。由此,頗有必要對這一階段使用Kotlin作一個簡單的小結。git

使用的Kotlin特性:

一.擴展函數

Kotlin容許開發者在不改變已有類的狀況下,爲某個類添加新的函數。這個特性叫作擴展函數。github

舉一個簡單的例子。若是要關閉一個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的使用。app

/** * 佔位符矩形 */
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和各類extension https://github.com/fengzhizi715/SAF-Kotlin-Utilside

二.尾隨閉包

一開始我並不瞭解這個概念。偶然間我看到咱們的小夥伴在使用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.InlineOnly
public 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技術棧:每週更新推送原創技術文章,歡迎掃描下方的公衆號二維碼並關注,期待與您的共同成長和進步。

相關文章
相關標籤/搜索