Android 开发中高阶函数的 10 个实例

news2025/1/15 12:47:37

Android 开发中高阶函数的 10 个实例

Kotlin 是一种现代编程语言,由于其表现力、简洁性和多功能性而变得越来越流行。它的关键特性之一是支持高阶函数,这使您可以编写更简洁、更灵活的代码。高阶函数是一种将一个或多个函数作为参数或返回一个函数作为结果的函数。在 Kotlin 中,我们可以使用 lambda 表达式、匿名函数或命名函数来定义高阶函数。
kotlin higher function
以下是 Android 开发人员如何在他们的项目中使用高阶函数:

事件监听器

事件监听器是 Android 开发中高阶函数的常见用例。例如,考虑以下将高阶函数作为参数来处理按钮单击事件的函数:

fun View.onClick(action: () -> Unit) {
    setOnClickListener { action() }
}

此函数扩展View类并采用将在单击视图时执行的 lambda 表达式。该setOnClickListener方法用于为视图设置点击监听器,当点击事件发生时执行lambda表达式。

使用此功能,我们可以轻松地以简洁易读的方式处理按钮单击事件:

button.onClick { 
    Toast.makeText(context, "Button clicked", Toast.LENGTH_SHORT).show() 
}

在这里,我们传递了一个 lambda 表达式,该表达式在单击按钮时显示 toast 消息。该onClick函数负责为按钮设置点击监听器,并在点击事件发生时执行 lambda 表达式。

视图动画

视图动画是 Android 开发中的一项常见任务,可以通过使用高阶函数使其更具可重用性和灵活性。View以下是使用高阶函数为不同属性设置动画的类的扩展函数示例:

fun View.animateProperty(
    property: KProperty0<Float>,
    fromValue: Float,
    toValue: Float,
    duration: Long,
    onComplete: () -> Unit = {}
) {
    val animator = ObjectAnimator.ofFloat(this, property.name, fromValue, toValue).apply {
        setDuration(duration)
        addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator?) {
                onComplete()
            }
        })
    }
    animator.start()
}

此函数在指定的持续时间内将视图的单个属性(例如其 X 或 Y 坐标)从起始值动画化到结束值。它还需要一个可选的回调函数,以便在动画完成时执行。

我们可以像这样在我们的代码中使用这个函数:

view.animateProperty(
    View.TRANSLATION_X,
    fromValue = 0f,
    toValue = 100f,
    duration = 500,
    onComplete = { onAnimationComplete() }
)

此代码为对象的 X 平移属性设置动画View,从其当前位置 (0) 到新位置 (100),时间超过 500 毫秒。当动画完成时,onAnimationComplete()将调用该函数。

RecyclerView

RecyclerView 是 Android 应用程序中常用的 UI 组件,用于显示项目列表或网格。它可以使用各种布局管理器和适配器进行定制,以适应不同的用例。在高阶函数的上下文中,RecyclerView 可以与高阶函数结合使用,以在代码中提供更多的灵活性和模块化。

RecyclerView 用作高阶函数的一个示例是创建一个接收项目列表的函数和一个将每个项目绑定到视图持有者的函数,并返回配置的 RecyclerView 适配器。这是一个示例实现:

fun <T> RecyclerView.bindData(
    data: List<T>,
    layoutRes: Int,
    bindFunc: (View, T) -> Unit,
    clickListener: ((T) -> Unit)? = null
) {
    adapter = object : RecyclerView.Adapter<ViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
            val view = LayoutInflater.from(parent.context).inflate(layoutRes, parent, false)
            return ViewHolder(view)
        }
        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            val item = data[position]
            bindFunc(holder.itemView, item)
            clickListener?.let { listener ->
                holder.itemView.setOnClickListener { listener(item) }
            }
        }
        override fun getItemCount() = data.size
        inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
    }
}

在这个函数中,data是RecyclerView中要显示的项目列表,layoutRes是每个项目视图的布局资源ID,bindFunc是将每个项目绑定到其对应的视图持有者的函数,clickListener是处理项目点击事件的可选函数。该函数返回一个 RecyclerView 适配器,该适配器配置为使用提供的布局和绑定函数显示项目。

使用此函数,我们可以创建一个 RecyclerView 并使用单个函数调用用数据填充它,如下所示:

recyclerView.bindData(
    data = listOf("item1", "item2", "item3"),
    layoutRes = R.layout.list_item,
    bindFunc = { view, item -> view.findViewById<TextView>(R.id.text_view).text = item },
    clickListener = { item -> onItemClick(item) }
)

此代码创建一个 RecyclerView,将其数据设置为字符串列表,并使用绑定函数将每个项目视图的文本设置为相应的字符串。它还设置了一个单击侦听器,该侦听器onItemClick使用单击的项目调用该函数。

线程

线程是许多编程语言中高阶函数的常见用例。可以使用高阶函数来简化在单独线程上运行代码的过程,从而更容易处理异步操作。

例如,在 Kotlin 中,我们可以定义一个以 lambda 为参数的函数,并在后台线程中运行它。此功能可用于避免阻塞 UI 线程并提供更流畅的用户体验。这是一个例子:

fun <T> runOnBackgroundThread(backgroundFunc: () -> T, callback: (T) -> Unit) {
    val handler = Handler(Looper.getMainLooper())
    Thread {
        val result = backgroundFunc()
        handler.post { callback(result) }
    }.start()
}

此函数将两个函数作为参数:backgroundFunc,它在后台线程上执行昂贵的计算,以及callback,它在主线程上调用计算结果。

该函数在单独的线程上完成其工作后,runOnBackgroundThread使用 aHandler将callback函数backgroundFunc发布到主线程。

使用这个高阶函数,我们可以在后台线程上运行昂贵的计算,并在主线程上用结果更新 UI,而不必担心线程的细节。

例如,我们可以runOnBackgroundThread这样调用函数:

runOnBackgroundThread(
    { doExpensiveCalculation() },
    { onResultLoaded(it) }
)

此代码传入执行耗时计算的 lambda 表达式和处理计算结果的backgroundFunc lambda 表达式。

权限处理

权限处理是移动应用程序开发中的一项常见任务,它通常涉及用于检查和请求权限的重复代码。简化此代码的一种方法是使用高阶函数。

例如,我们可以定义一个函数withPermissions,该函数接受请求的权限列表和一个在授予权限时执行的回调函数。此函数将处理权限检查和请求,并仅在授予权限时调用回调函数。

这是 Kotlin 中的示例实现:

fun Activity.withPermissions(vararg permissions: String, callback: () -> Unit) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        val ungrantedPermissions = permissions.filter {
            checkSelfPermission(it) == PackageManager.PERMISSION_DENIED
        }
        if (ungrantedPermissions.isEmpty()) {
            // All permissions are granted, execute callback
            callback()
        } else {
            // Request permissions
            requestPermissions(ungrantedPermissions.toTypedArray(), 0)
        }
    } else {
        // Pre-Marshmallow devices, execute callback
        callback()
    }
}

这个函数可以这样使用:

withPermissions(
    Manifest.permission.CAMERA,
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.WRITE_EXTERNAL_STORAGE
) {
    // Code to execute when permissions are granted
}

在这个例子中,我们定义了一个函数withPermissions,它接受可变数量的权限和一个回调函数作为参数。在函数内部,我们检查设备是否正在运行 Marshmallow 或更高版本,如果是,我们过滤权限列表以仅包含尚未授予的权限。如果已经授予所有权限,我们立即执行回调函数。否则,我们使用该方法请求未授予的权限requestPermissions。最后,如果设备运行的是 Marshmallow 之前的 Android 版本,我们会立即执行回调函数而不检查权限。

输入验证

输入验证可以作为高阶函数实现,它将验证函数作为参数并返回可用于验证输入的函数。这是一个示例实现:

fun String.validate(validationFunc: (String) -> Boolean): Boolean {
    return validationFunc(this)
}

validate在这个例子中,我们定义了一个在类上调用的扩展函数String。该validate函数采用单个参数,这是一个验证函数,它采用输入String并返回Boolean指示输入是否有效的指示。该validate函数将验证函数应用于String调用它的对象并返回结果。

下面是一个使用示例:

val input = "example input"
val isInputValid = input.validate { input -> input.isNotEmpty() }

在这个例子中,我们创建了一个String名为 called 的对象input,然后调用validate它的函数,传递一个 lambda 来检查字符串是否不为空。如果输入有效则函数返回,否则validate返回。

委托

委托是面向对象编程中的一种技术,其中一个对象将其某些职责传递给另一个对象。在 Kotlin 中,委托是使用by关键字实现的。

作为委托作为高阶函数的示例,我们可以考虑一个lazy函数,该函数返回延迟初始化的属性的委托。该lazy函数以一个 lambda 函数作为参数,并返回一个委托,该委托将在第一次访问时调用 lambda 函数来惰性初始化该属性。

这是一个例子:

fun <T> lazyDelegate(initializer: () -> T) = lazy(initializer)::getValue

class Example {
    val lazyProperty: String by lazyDelegate {
        println("Initializing lazy property")
        "Hello, World!"
    }
}

fun main() {
    val example = Example()
    println(example.lazyProperty)
    println(example.lazyProperty)
}

在此示例中,lazyDelegate函数采用返回属性初始值的 lambda 函数。lazy它使用函数创建委托lazy并返回getValue委托的函数。该getValue函数将在第一次访问属性时调用 lambda 函数来初始化属性并返回值。

该类Example定义了一个lazyProperty使用函数延迟初始化的属性lazyDelegate。传递给函数的 lambda 函数向lazyDelegate控制台打印一条消息并返回字符串“Hello, World!”。

在该main函数中,我们创建了该类的一个实例Example并访问了该lazyProperty属性两次。我们第一次访问它时,会调用 lambda 函数来初始化属性,并在控制台打印消息“Initializing lazy property”。第二次访问时,属性已经初始化,所以不会再调用lambda函数,取值为“Hello, World!” 立即返回。

日志记录

日志记录是软件开发中用于记录有关应用程序行为或状态的信息的常用技术。它可用于调试问题、监控性能或跟踪用户行为。在许多情况下,日志记录可以作为高阶函数来实现。

下面是一个在 Kotlin 中作为高阶函数记录日志的例子:

fun <T> log(tag: String, message: String, function: () -> T): T {
    Log.d(tag, message)
    val result = function()
    Log.d(tag, "Function result: $result")
    return result
}

在这个例子中,log是一个高阶函数,它接受一个标签、一条消息和一个函数作为参数。该函数被执行,其返回值与消息和标签一起被记录下来。

这是此函数的示例用法:

val result = log("myTag", "Calculating result...") {
    // Perform some expensive calculation
    42
}

在此示例中,该log函数用于在执行耗时的计算之前和之后记录一条消息。然后返回计算结果并将其存储在result变量中。

Room Database

Room Database 是一个流行的库,用于在 Android 中使用 SQLite 数据库。Room 提供了一组注释和类,可帮助您定义数据库并与之交互。您可以使用高阶函数来简化使用 Room 的过程。

下面是一个高阶函数的例子,它接受一个 Room DAO 对象和一个执行数据库查询的 lambda 函数:

fun <T> runInTransaction(dao: MyDao, action: () -> T): T {
    return dao.runInTransaction {
        action()
    }
}

在此示例中,该runInTransaction函数采用一个MyDao对象和一个执行数据库操作的 lambda 函数。该runInTransaction函数调用对象MyDao上的方法runInTransaction,该方法在数据库事务中执行 lambda 函数。lambda 函数可以返回一个值,该值由runInTransaction函数返回。

以下是如何使用该runInTransaction函数执行数据库查询的示例:

val dao = MyDatabase.getInstance(context).myDao()
val result = runInTransaction(dao) {
    dao.getSomeData()
}

在这个示例中,使用一个 MyDao 对象和一个调用 MyDao 对象上的 getSomeData 方法的 lambda 函数调用 runInTransaction 函数。runInTransaction 函数会为您处理数据库事务和错误处理,并返回 getSomeData 方法的结果。

Toast 处理

Toast 是在 Android 应用程序中向用户显示简短通知或反馈的常用方式。以下是如何使用高阶函数处理 toasts 的示例:

fun Context.showToast(message: String, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, message, duration).show()
}

fun Fragment.showToast(message: String, duration: Int = Toast.LENGTH_SHORT) {
    activity?.showToast(message, duration)
}

showToast在这个例子中,我们定义了一个为Context和调用的扩展函数Fragment。该函数接受一个message字符串和一个duration整数,后者指定 toast 应显示多长时间。

showToast函数Toast使用该makeText方法创建一个新的,然后使用该show方法显示它。该makeText方法接受字符串message和整数duration,toast 应显示的位置ContextActivity

使用这个高阶函数,我们可以轻松地在应用程序的任何位置显示Toast,如下所示:

showToast( "Hello, world!" )
我们还可以自定义吐司的持续时间:

showToast( "Hello, world!" , Toast.LENGTH_LONG)

结论

总而言之,高阶函数是函数式编程中的一个重要概念,它允许函数接受其他函数作为参数或将它们作为值返回。它们提供了一种灵活且可重用的方式来执行常见任务,例如线程、输入验证、日志记录、依赖项注入等。

在上面提供的示例中,我们已经看到如何使用高阶函数来简化代码并使其更具可读性和可维护性。它们允许关注点分离,并提供了一种跨应用程序不同部分重用代码的方法。无论是处理权限、输入验证、数据库操作还是导航,高阶函数都提供了一个强大的工具来简化复杂的任务。

虽然高阶函数可能需要一些时间才能掌握,但一旦理解,它们可以极大地提高代码的质量和可维护性。因此,它们是添加到任何开发人员工具包中的宝贵技术。

参考

https://medium.com/@summitkumar/10-practical-examples-of-higher-order-functions-in-android-development-84e9c6a4bdc3

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

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

相关文章

python+java+nodejs基于vue的企业人事工资管理系统

根据系统功能需求分析&#xff0c;对系统功能的进行设计和分解。功能分解的过程就是一个由抽象到具体的过程。 作为人事数据库系统&#xff0c;其主要实现的功能应包括以下几个模块&#xff1a; 1.登录模块 登录模块是由管理员、员工2种不同身份进行登录。 2.系统管理模块 用户…

工具抓包Charles配置HTTPS步骤

charles抓取HTTPS设置&#xff0c;详细踩坑版 写这篇文章的背景就是&#xff0c;每次我在一台新电脑上用charles抓包时&#xff0c;总是因为各种原因无法抓到https请求&#xff0c;每个百度出来的回答又不是那么详细&#xff0c;需要通过几篇回答才能解决过程中的各种问题&…

C++程序员的职业前景怎么样?来谈谈我自己的想法

我之前提到了程序员在二线城市的大概待遇。今天&#xff0c;我要说一下普通程序员的职业前景。因为最初阶段的工资可能比较高&#xff0c;但如果没有可持续性&#xff0c;这就不是一个特别好的工作。 从我自身的经验来看&#xff0c;我们公司的程序员主要有两条路线。一条是纯…

【存储数据恢复】NetApp存储WAFL文件系统数据恢复案例

存储数据恢复环境&#xff1a; NetApp存储设备&#xff0c;WAFL文件系统&#xff0c;底层是由多块硬盘组建的raid磁盘阵列。 存储故障&#xff1a; 工作人员误操作导致NetApp存储内部分重要数据被删除。 存储数据恢复过程&#xff1a; 1、将存储设备的所有磁盘编号后取出&…

软考A计划-常用公式复习

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

使用Nginx做反向代理

使用Nginx做反向代理 文章目录 使用Nginx做反向代理代理HTTP请求代理HTTPS请求举个大栗子 代理HTTP请求 按照以下步骤使用Nginx做反向代理&#xff1a; 编辑 Nginx 的配置文件。默认情况下&#xff0c;Nginx 的配置文件位于 /etc/nginx/nginx.conf。 sudo nano /etc/nginx/ngi…

1703_LibreOffice常用功能使用体验

全部学习汇总&#xff1a; GreyZhang/windows_skills: some skills when using windows system. (github.com) 首先需要说明的是我不是一个重度Office用户&#xff0c;甚至算不上一个重度的Office用户。我使用的Office软件最多的功能就是文档编辑&#xff0c;绝大多数时候还是文…

【什么是苹果推信?什么是苹果推?】通过苹果手机Imessage进行信息推送的方式;

如今不少人都在利用苹果手机&#xff0c;重要是装备高端&#xff0c;很少呈现卡机的征象&#xff0c;并且星移斗换快&#xff0c;紧跟互联网期间成长的脚步。苹果手机是火了&#xff0c;谁又能想到另有比它更火的事变出现呢&#xff0c;便是苹果推信。苹果推信主要上风是推信群…

晋商银行“沧海”数据资产管理系统

案例名称 晋商银行“沧海”数据资产管理系统 案例简介 晋商银行“沧海”数据资产管理系统&#xff0c;取自“海纳百川、沧海一粟”之意&#xff0c;即数据如茫茫大海&#xff0c;其价值不可估量。该系统贯穿数据的全生命周期&#xff0c;包括数据多维度描述、数据…

期末复习自用--python

前言 python的优点&#xff1a; 简洁&#xff0c;语法优美&#xff0c;简单易学&#xff0c;开源&#xff0c;可移植性好&#xff0c;拓展性好&#xff0c;类库丰富&#xff0c;通用灵活&#xff0c;模式多样&#xff0c;良好的中文支持。 python的缺点&#xff1a; 执行效率不…

1.信息的表示和处理

基础 进制转换 字数据大小 寻址和字节顺序&#xff08;大小端&#xff09; 01 23 45 67 大端法&#xff1a;最高有效字节&#xff08;01&#xff09;在最前面&#xff08;相当于正序&#xff09; 小端法&#xff1a;最低有效字节&#xff08;67&#xff09;在最前面&#xff0…

Ceph入门到精通-CrushMap算法概述

下面是伪代码object到osd的伪代码 locator =object_name obj_hash =hash(locator) pg =obj_hash %num_pg OSDs_for_pg =crush(pg) # returns a list of OSDs primary =osds_for_pg[0] replicas =osds_for_pg[1:] defcrush(pg): all_osds=[osd.0,osd.1,osd.2,...] resu…

【Linux内核解析-linux-5.14.10-内核源码注释】内核常用链表宏解释

1、list_for_each_entry_safe 这段代码是一个宏定义&#xff0c;用于遍历一个链表中所有的元素&#xff0c;并且在遍历过程中可以安全地删除元素。具体来说&#xff0c;这个宏定义的功能是&#xff1a; 遍历链表中所有的元素&#xff0c;从头节点开始&#xff0c;直到尾节点结束…

读SQL进阶教程笔记15_SQL编程思维

1. 还原论 1.1. 认为可以把高级现象还原为低级基本现象的学说 1.2. 将复杂的东西看成是由简单单元组合而成的 1.2.1. 以赋值、条件分支、循环等作为基本处理单元&#xff0c;并将系统整体分割成很多这样的单元的思维方式 1.2.2. 文件系统也是将大量的数据分割成记录这样的小…

DOM事件(中)

常见的事件分类&#xff08;了解&#xff09; ●我们在写页面的时候经常用到的一些事件 ●大致分为几类&#xff0c;浏览器事件 / 鼠标事件 / 键盘事件 / 表单事件 / 触摸事件 ●不需要都记住&#xff0c;但是大概要知道 鼠标事件 ●click &#xff1a;点击事件 ●dblclick &a…

Python小姿势 - # 如何使用Python爬取网页数据

如何使用Python爬取网页数据 今天我们来学习一下如何使用Python来爬取网页数据。 首先&#xff0c;我们需要准备一个空白的文件&#xff0c;在文件中输入以下代码&#xff1a; import requests url http://www.baidu.com r requests.get(url) print(r.text) 上面的代码中&…

宝宝腹泻怎么办?儿科医生分享小儿腹泻的辩证和处理方法

小儿腹泻病是婴幼儿时期的常见病。面对腹泻&#xff0c;很多父母往往不知所措&#xff0c;甚至不知道该怎么处理&#xff0c;只能带宝宝去医院治疗。由于腹泻具有反复性&#xff0c;稍有护理不当&#xff0c;甚至会加重病情。那么&#xff0c;小儿腹泻药如何处理呢&#xff1f;…

微服务---Redis实用篇-黑马头条项目-登录功能(短信验证缓存,用户信息缓存)

黑马头条项目-登录功能(短信验证缓存,用户信息缓存) 1、短信登录 1.1、导入黑马点评项目 1.1.1 、导入SQL 1.1.2、有关当前模型 手机或者app端发起请求&#xff0c;请求我们的nginx服务器&#xff0c;nginx基于七层模型走的事HTTP协议&#xff0c;可以实现基于Lua直接绕开t…

Android之WindowManager介绍

WindowManager android中真正展示给用户的是window和view. activity在android中所其的作用主要是处理一些逻辑问题&#xff0c;比如生命周期的管理、建立窗口等。 在android中&#xff0c;窗口的管理还是比较重要的一块&#xff0c;因为他直接负责把内容展示给用户&#xff…

11.streamFile

1.Stream流 1.1体验Stream流【理解】 案例需求 按照下面的要求完成集合的创建和遍历 创建一个集合&#xff0c;存储多个字符串元素把集合中所有以"张"开头的元素存储到一个新的集合把"张"开头的集合中的长度为3的元素存储到一个新的集合遍历上一步得到的集…