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

本文已同步发表于我的微信公众号,搜索 代码说 即可关注,欢迎与我沟通交流。


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 里都有什么:

在这里插入图片描述
列举一些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
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
全新RDIFramework.NET V5.1版本发布。降低开发成本,提高产品质量,提升用户体验与开发团队稳定性,做软件就选RDIFramework.NET敏捷开发框架。 RDIFramework.NET敏捷开发框架,是我司重磅推出的基于全新.NET Framework与.NET Core的快速信息化系统开发、整合框架,为企业快速构建跨平台、企业级的应用提供了强大支持。 开发人员不需要开发系统的基础功能和公共模块,框架自身提供了强大的函数库和开发包,开发人员只需集中精力专注于业务部分的开发,因此大大提高开发效率和节约开发成本。框架采用主流的C#语言开发完成,支持多种数据库类型,支持Web、WinForm,支持Framework与Core双引擎。 使用RDIFramework.NET敏捷开发框架能提高管理类软件系统的整体质量、提高模块与模块之间的兼容性、提高代码的重复利用率,使软件系统架构更加合理、质量更加过硬,使得劳动成果最大程度上重复利用。 框架基础模块包括:强大灵活的权限控制组件,模块分配与管理组件,灵活易用的工作流组件、数据字典管理组件、在线表单设计组件、丰富的报表统计组件、即时通讯(IM)组件、邮件中心组件、微信开发相关组件、任务调度组件、自动升级组件、多语言模块,各种常用的商业控件,强大的代码生成器,开发实例、丰富的基础类库、开发辅助工具等各基础常用功能组件。 框架提供的大量通用插件,支持Saas多租户模式,完成功能的开发就像搭积木一样,只需要把各种组件进行组合拼装,拼装好了系统的开发也就完成了。应用系统建立在此框架之上,采用构件式、可复用开发,节省开发成本,加快开发速度,在软件开发上更好的做到多快省。 适合低中高任意开发水平的开发者,可以开发OA、ERP、BPM、CRM、WMS、TMS、MIS、BI、电商平台后台、物流管理系统、医院管理系统、快递管理系统、教务管理系统等各类管理软件、支持大并发、SaaS应用。代码稳定、组件丰富、功能强大、无限扩展。由框架开发团队的原班人马直接提供技术支持,为您顺利完成开发工作保驾护航。不管您是零基础还是专业开发人员,都能轻松驾驭这套开发框架。 ------------------------------------------------------------------------------------------------------------------ 一路走来数个年头,感谢RDIFramework.NET框架的支持者与使用者,大家可以通过下面的地址了解详情。 RDIFramework.NET官方网站:http://www.rdiframework.net/ RDIFramework.NET官方博客:http://blog.rdiframework.net/ 特别说明,框架相关的技术文章请以官方网站为准,欢迎大家收藏! RDIFramework.NET框架由海南国思软件科技有限公司专业团队长期打造、一直在更新、一直在升级,请放心使用! 欢迎关注RDIFramework.NET框架官方微信公众号(微信号:guosisoft),及时了解最新动态。
全新RDIFramework.NET V5.1版本发布。降低开发成本,提高产品质量,提升用户体验与开发团队稳定性,做软件就选RDIFramework.NET敏捷开发框架。 RDIFramework.NET敏捷开发框架,是我司重磅推出的基于全新.NET Framework与.NET Core的快速信息化系统开发、整合框架,为企业快速构建跨平台、企业级的应用提供了强大支持。 开发人员不需要开发系统的基础功能和公共模块,框架自身提供了强大的函数库和开发包,开发人员只需集中精力专注于业务部分的开发,因此大大提高开发效率和节约开发成本。框架采用主流的C#语言开发完成,支持多种数据库类型,支持Web、WinForm,支持Framework与Core双引擎。 使用RDIFramework.NET敏捷开发框架能提高管理类软件系统的整体质量、提高模块与模块之间的兼容性、提高代码的重复利用率,使软件系统架构更加合理、质量更加过硬,使得劳动成果最大程度上重复利用。 框架基础模块包括:强大灵活的权限控制组件,模块分配与管理组件,灵活易用的工作流组件、数据字典管理组件、在线表单设计组件、丰富的报表统计组件、即时通讯(IM)组件、邮件中心组件、微信开发相关组件、任务调度组件、自动升级组件、多语言模块,各种常用的商业控件,强大的代码生成器,开发实例、丰富的基础类库、开发辅助工具等各基础常用功能组件。 框架提供的大量通用插件,支持Saas多租户模式,完成功能的开发就像搭积木一样,只需要把各种组件进行组合拼装,拼装好了系统的开发也就完成了。应用系统建立在此框架之上,采用构件式、可复用开发,节省开发成本,加快开发速度,在软件开发上更好的做到多快省。 适合低中高任意开发水平的开发者,可以开发OA、ERP、BPM、CRM、WMS、TMS、MIS、BI、电商平台后台、物流管理系统、医院管理系统、快递管理系统、教务管理系统等各类管理软件、支持大并发、SaaS应用。代码稳定、组件丰富、功能强大、无限扩展。由框架开发团队的原班人马直接提供技术支持,为您顺利完成开发工作保驾护航。不管您是零基础还是专业开发人员,都能轻松驾驭这套开发框架。 ------------------------------------------------------------------------------------------------------------------ 一路走来数个年头,感谢RDIFramework.NET框架的支持者与使用者,大家可以通过下面的地址了解详情。 RDIFramework.NET官方网站:http://www.rdiframework.net/ RDIFramework.NET官方博客:http://blog.rdiframework.net/ 特别说明,框架相关的技术文章请以官方网站为准,欢迎大家收藏! RDIFramework.NET框架由海南国思软件科技有限公司专业团队长期打造、一直在更新、一直在升级,请放心使用! 欢迎关注RDIFramework.NET框架官方微信公众号(微信号:guosisoft),及时了解最新动态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_小马快跑_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值