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

news2024/11/25 10:50:16

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

文章目录

      • runCatching代替try catch
      • View的可见性
      • dp、sp、px之间相互转换
      • by lazy 替代findViewById
      • Toast、Log

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/754034.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Day52| 300.最长递增子序列 、 674. 最长连续递增序列 、718. 最长重复子数组

300.最长递增子序列 1.题目&#xff1a; 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 …

从编写metadata.yaml到测试processor文件成功

检查模型和客户端&#xff08; Excel 原型图&#xff09;字段是否对应 修改 applications\commands\metadata\cai_liao_ she_bei_metadata.yaml 文件 wen_jian_db_conf 下的 all 下的 content_field_name 选项&#xff0c;要根据 model 中写的文件路径找到对应的 model&#x…

论文阅读—2023.7.13:遥感图像语义分割空间全局上下文信息网络(主要为unet网络以及改unet)附加个人理解与代码解析

前期看的文章大部分都是深度学习原理含量多一点&#xff0c;一直在纠结怎么改模型&#xff0c;论文看的很吃力&#xff0c;看一篇忘一篇&#xff0c;总感觉摸不到方向。想到自己是遥感专业&#xff0c;所以还是回归遥感影像去谈深度学习&#xff0c;回归问题&#xff0c;再想着…

resultType和parameterType的基本使用和区别

我们在使用Mybatis的过程中不难发现Mapper文件中的select,insert,update,delect操作中都有一个parameterType 或 resultType属性。 resultType&#xff1a;返回值类型&#xff0c;类型即为对象类型&#xff0c;返回结果字段与对象属性匹配映射&#xff0c;类型中的属性名要与查…

数学建模-假设检验

原假设&#xff0c;备择假设P值&#xff0c;显著性水平单侧建议&#xff0c;双侧检验

IPUU的小工具拍了拍你(上)

IPUU是埃文科技旗下的综合性IP查询网站&#xff0c;提供多维度的IP数据信息。通过在线查询&#xff0c;用户可以获取目标IP地址的详尽信息&#xff0c;包括位置属性、网络属性、风险属性以及业务属性等&#xff0c;同时还可以查询域名信息。无论您是需要查看某个IP地址归属地&a…

VBA技术资料1-120

MF系列VBA技术资料 为了让广大学员在实际VBA编程中有切实可行的思路及有效的提高自己的编程技巧&#xff0c;我参考大量的资料&#xff0c;并结合自己的经验总结了这份MF系列VBA技术综合资料&#xff0c;而且开放源码&#xff08;MF04除外&#xff09;&#xff0c;其中MF01-04属…

一篇文章让你搞懂内存函数

内存操作函数 memcpy 库函数memcmp介绍 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。 这个函数在遇到 ‘\0’ 的时候并不会停下来。 如果source和destination有任何的重叠&#xff0c;复制的结果都是未定义的。 库函数memcmp的代码形式 v…

Ubuntu使用Samba设置共享文件夹提示“拒绝访问”的解决办法一

问题&#xff1a;看图片 IP正确&#xff0c;用户名也对。 解决&#xff1a;重新设置密码 sudo smbpasswd -a topeet 添加成功

详解CAS算法

CAS的全称是 Compare And Swap&#xff08;比较并交换&#xff09;&#xff0c;它是并发编程中的一个重要概念。本文结合Java的多线程操作来讲解CAS算法。 CAS算法的优势是可以在不加锁的情况下保证线程安全&#xff0c;从而减少线程之间的竞争和开销。 目录 一、CAS算法的内…

979. 在二叉树中分配硬币(力扣)

在二叉树中分配硬币 题目一题一解&#xff1a;DFS(java)思路步骤解析测试代码复杂度分析运行结果 优化代码思路测试代码运行结果复杂度分析 题目 给你一个有 n 个结点的二叉树的根结点 root &#xff0c;其中树中每个结点 node 都对应有 node.val 枚硬币。整棵树上一共有 n 枚…

韦东山-BeagleV-Ahead TH1520 RISC-V 高性能开发板开箱硬件评测

BeagleV-Ahead开箱硬件讲解 BeagleV-Ahead开箱介绍 非常感谢 中国杭州平头哥半导体优先公司 和 Beagle社区给予我们 全球首款高性能 TH1520 RISC-V SBC开发板 BeagleV-Ahead评测工作&#xff0c;我们将围绕 开发板 外观 &#xff0c;板载功能接口&#xff0c;系统启动系统初体…

AcWing 107. 超快速排序—逆序对

问题链接: AcWing 107. 超快速排序 问题描述 分析 这道题考查的算法不难&#xff0c;就只是利用归并排序来求逆序对的数量&#xff0c;但是主要是如何分析问题&#xff0c;如何能从问题中看出来和逆序对数量有关&#xff0c;现在的题目基本上很少是那种模板算法题了&#xff…

力扣21. 合并两个有序链表

题目 将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 链接&#xff1a;21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09; 题解 设置两个指针head和tail&#xff0c;head用来指向新链表的头结点&#xff0c;tail…

HCIA初级考试题目(复制粘贴命令修改满分试卷)

要求&#xff1a; &#xff08;设备名称按照拓扑标识修改&#xff0c;注意区分大小写&#xff09; 1、ISP路由器仅配置IP地址 2、test-1和test-2仅作为代替终端设备进行测试使用&#xff0c;路由采用静态路由 3、R1/R2之间使用OSPF做到内网全通&#xff0c;单区域&#xff0c;O…

3.6.cuda运行时API-共享内存的学习

目录 前言1. 共享内存2. shared memory案例3. 补充知识总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习精简 CUDA 教程-共享…

前端vue入门(纯代码)32_编程式路由导航

星光不问赶路人&#xff0c;时光不负有心人 【30.Vue Router--编程式导航】 除了使用 <router-link> 创建 a 标签来定义导航链接&#xff0c;我们还可以借助 $router 的实例方法&#xff0c;通过编写代码来实现。 编程式路由导航的5种方法 我们先看一下组件实例中的t…

掌握这几招,让你的CTA按钮更吸引人点击

CTA全称Call-To-Action&#xff0c;是行为召唤按钮&#xff0c;是App和网页设计中的关键元素。 在落地页设计制作中&#xff0c;CTA按钮是用户在访问页面后引导用户去点击并且跳转至下一个流程&#xff08;如购买、联系、提交等行为&#xff09;的按钮控件。其核心目标是引导用…

函数图形化显示练习(进阶)

运行代码: //函数图形化显示练习&#xff08;进阶&#xff09; #include"std_lib_facilities.h" #include"GUI/Simple_window.h" #include"GUI/GUI.h" #include"GUI/Graph.h" #include"GUI/Point.h" //定义函数 double one…

【Spring Cloud系列】Hystrix应用详解

【Spring Cloud系列】Hystrix应用详解 文章目录 【Spring Cloud系列】Hystrix应用详解一、概述二、什么是Hystix三、Hystrix作用四、Hystrix设计原则五、Hystrix实现原理5.1 隔离5.2 熔断5.3 降级服务降级主要用于什么场景呢实现服务降级需要考虑几个问题降级分类 5.4 缓存请求…