本文已同步发表于我的微信大众号,查找 代码说 即可重视,欢迎与我沟通交流。

Kotlin 中扩展函数是一种允许在已有的类中增加新函数,而无需修改类定义或承继该类。经过运用扩展函数,咱们能够轻松地为现有代码增加新功能和增强功能,下面就罗列几个有用的扩展函数。

runCatching代替try catch

  • try catch 办法:
try {
   100 / 0
} catch (ex: Throwable) {
   ex.printStackTrace()
}
  • runCatching 办法:
runCatching { 100 / 0 }
   .onFailure { ex -> ex.printStackTrace() }

假如不关心回来值,到这儿就结束了,运用起来是不是更简单一些。假如需求持续对lambda表达式中的计算成果进行处理,那么持续往下看。

runCatching是在Kotlin 1.3版本新增的,看下源码

@InlineOnly
@SinceKotlin("1.3")
public inline fun <T, R> T.runCatching(block: T.() -> R): Result<R> {
    return try {
        Result.success(block())
    } catch (e: Throwable) {
        Result.failure(e)
    }
}

能够看到runCatching函数是一个扩展函数,函数承受一个lambda表达式block作为参数,并在T目标上履行这个lambda表达式,函数内部帮咱们增加了try catch

  • 假如lambda表达式成功履行并回来成果,则运用Result.success将成果包装成Result类型并回来;
  • 假如出现反常,则运用Result.failure将反常包装成Result类型并回来。

看下 Result 里都有什么:

提高开发效率!5个对开发者有用的Kotlin扩展函数
罗列一些Result中的常用函数:

runCatching { 100 / 0 }
   .onSuccess { value -> log("onSuccess:$value") } //runCatching{}中履行成功,并传入履行成果
   .onFailure { exception -> log("onFailure:$exception") } //runCatching{}中履行失败,并传入exception
   //.getOrDefault(0) //获取runCatching{}中履行的成果,假如是Failure直接回来默认值
   .getOrElse { ex -> //获取runCatching{}中履行的成果,假如是Failure回来else内部的值。相比getOrDefault多了对exception的处理
       log("exception:$ex")
       100
    }
    //.getOrThrow()//获取runCatching{}中履行的成果,假如是Failure直接抛反常
    //.getOrNull() //获取runCatching{}中履行的成果,假如是Failure回来null
    //.exceptionOrNull() //假如有问题则回来exception;否则回来null
    .run {
       log("result:$this")
    }

履行成果:

E/TTT: onFailure:java.lang.ArithmeticException: divide by zero
E/TTT: exception:java.lang.ArithmeticException: divide by zero
E/TTT: result:100

尽管100/0抛出了反常,还是能够经过getOrElse中从头赋值,并最终把值输出出来,假如需求其他处理,能够运用上述示例中的其他函数,按需运用即可。

假如改为runCatching { 100 / 2 },其他代码不变,则输出成果:

E/TTT: onSuccess:50
E/TTT: result:50

View的可见性

fun View?.visible() {
    if (this?.visibility != View.VISIBLE) {
        this?.visibility = View.VISIBLE
    }
}
fun View?.invisible() {
    if (this?.visibility != View.INVISIBLE) {
        this?.visibility = View.INVISIBLE
    }
}
fun View?.gone() {
    if (this?.visibility != View.GONE) {
        this?.visibility = View.GONE
    }
}

运用它们:

val toolbar: Toolbar = findViewById(R.id.toolbar)
toolbar.visible() //设置visible
toolbar.invisible() //设置invisible
toolbar.gone()  //设置gone

dp、sp、px之间相互转换

//dp转px
fun Number.dp2px(): Int {
    return ScreenUtil.dp2px(MyApplication.getApplication(), toFloat())
}
//sp转px
fun Number.sp2px(): Int {
    return ScreenUtil.sp2px(MyApplication.getApplication(), toFloat())
}
//px转dp
fun Number.px2dp(): Int {
    return ScreenUtil.px2dp(MyApplication.getApplication(), toFloat())
}
//px转sp
fun Number.px2sp(): Int {
    return ScreenUtil.px2sp(MyApplication.getApplication(), toFloat())
}
object ScreenUtil {
    fun dp2px(@NonNull context: Context, dp: Float): Int {
        val scale = context.resources.displayMetrics.density
        return (dp * scale + 0.5f).toInt()
    }
    fun px2dp(@NonNull context: Context, px: Float): Int {
        val scale = context.resources.displayMetrics.density
        return (px / scale + 0.5f).toInt()
    }
    fun sp2px(@NonNull context: Context, spValue: Float): Int {
        val fontScale = context.resources.displayMetrics.scaledDensity
        return (spValue * fontScale + 0.5f).toInt()
    }
    fun px2sp(@NonNull context: Context, pxValue: Float): Int {
        val fontScale = context.resources.displayMetrics.scaledDensity
        return (pxValue / fontScale + 0.5f).toInt()
    }
}

运用它们:

100.dp2px()
100.sp2px()
100.px2dp()
100.px2sp()

by lazy 代替findViewById

by lazy是属性延迟托付,关于托付机制的用法拜见:Kotlin | 10分钟搞定by托付机制。

fun <T : View> Activity.id(id: Int) = lazy {
    findViewById<T>(id)
}

Activity中运用:

class DemoActivity : AppCompatActivity() {
     private val mToolBar: Toolbar by id(R.id.toolbar)
     override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_xxx)
    }
}

经过by lazy简化了控件的创立流程,避免每次创立都去调用findViewById(id),跟Butterknife的用法很类似。

假如是在Fragment中运用呢?首要Fragment中并没有findViewById(id)函数,所以需求略微改造一下:

interface IRootView {
    fun rootView(): View
}
//留意,这儿声明的是IRootView的扩展函数
fun <T : View> IRootView.id(id: Int) = lazy {
    this.rootView().findViewById<T>(id)
}
abstract class BaseFragment : Fragment(), IRootView {
    private var mRootView: View? = null
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        if (mRootView == null) {
            mRootView = inflater.inflate(getLayoutId(), container, false)
        }
        return mRootView
    }
    override fun rootView(): View {
        return mRootView!!
    }
    @LayoutRes
    abstract fun getLayoutId(): Int
}
  • IRootView接口中只有一个rootView()办法,回来类型为android.view.View
  • 扩展函数id<T : View>()是针对完成IRootView的目标进行扩展的。该函数需求传入Int类型参数表明控件ID,在调用时会运用lazy托付形式延迟初始化并回来T类型(泛型)控件。
  • BaseFragment承继自Fragment而且完成了IRootview接口。同时其内部也维护着mRootview变量用于缓存视图,在 onCreateView 办法中创立视图,并将其保存到变量mRootview中以便后边复用。

子类Fragment中运用:

class DemoFragment : BaseFragment() {
    private val mToolBar: Toolbar by id(R.id.toolbar)
    override fun getLayoutId(): Int = R.layout.fragment_demo
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        mToolBar.xxx //能够直接运用了
    }
}

Toast、Log

fun Activity.showToast(msg: String, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, msg, duration).show()
}
fun Activity.showToast(@StringRes msg: Int, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, msg, duration).show()
}
fun Fragment.showToast(msg: String, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(requireContext(), msg, duration).show()
}
fun Fragment.showToast(@StringRes message: Int, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(requireContext(), message, duration).show()
}
fun log(msg: String, tag: String = "TAG") {
    if (!BuildConfig.DEBUG) return
    Log.d(tag, msg)
}

运用它:

showToast(R.string.action_settings) //1
showToast("棒棒哒", Toast.LENGTH_LONG) //2
log("log展示") //3

欢迎扫描下方二维码或查找微信大众号 代码说, 重视我的微信大众号检查最新文章~

提高开发效率!5个对开发者有用的Kotlin扩展函数