当前位置: 首页 > news >正文

Kotlin 优雅的接口实现

1. 日常遇到的冗余的接口方法实现

日常开发中,经常会要实现接口,但是很多场景中,只需要用到其中一两个方法,例如 ActivityLifecycleCallbacks,它有很多个接口需要实现,但是很多时候我们只需要用到其中的一两个

    val myActivityLifecycleCallbacks = object : Application.ActivityLifecycleCallbacks  {/*** 例如我们只需要监听 Activity 的创建和销毁,那么 onActivityStarted, onActivityResumed, onActivityPaused* onActivityStopped,onActivityStopped,onActivitySaveInstanceState 这 6 个方法是完全没必要是做实现的,* 即使是空实现*/override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {TODO("Not yet implemented")}override fun onActivityStarted(activity: Activity) {TODO("Not yet implemented")}override fun onActivityResumed(activity: Activity) {TODO("Not yet implemented")}override fun onActivityPaused(activity: Activity) {TODO("Not yet implemented")}override fun onActivityStopped(activity: Activity) {TODO("Not yet implemented")}override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {TODO("Not yet implemented")}override fun onActivityDestroyed(activity: Activity) {TODO("Not yet implemented")}}

如果有多个不同业务需要实现这个接口,就这样很容易产生代码冗余。有没有一种优雅的方式,只需要实现自己需要的方法而不再需要去关注其他方法?有的,那就是利用 Java 的动态代理和 kotlin 的委托模式

2. 利用 Java 的动态代理和 Kotlin 的委托模式

首先需要实现一个通用的动态代理,新建一个 Kotlin 文件 DelegateObject.kt,这里通过 inlinereified 关键字,获取到泛型的 class 信息

import java.lang.reflect.InvocationHandler
import java.lang.reflect.Proxyinline fun <reified T> noOpDelegate() : T {val javaClass = T::class.javareturn Proxy.newProxyInstance(javaClass.classLoader, arrayOf(javaClass), no_op_invocationHandler) as T
}val no_op_invocationHandler = InvocationHandler { _, _, _ -> }

这样就可以获取到任意一个接口的一个对象,只是没有具体的实现。接着再利用 Kotlin 的 by 关键字实现对象委托

    val myActivityLifecycleCallbacks = object : Application.ActivityLifecycleCallbacks by noOpDelegate() {}

由于 Kotlin 委托模式的原理,实际上在编译期间也是会生成 ActivityLifecycleCallbacks 的所有方法,先来看看转译后的实现

   private final Application.ActivityLifecycleCallbacks myActivityLifecycleCallbacks = (Application.ActivityLifecycleCallbacks)(new Application.ActivityLifecycleCallbacks() {// $FF: synthetic fieldprivate final Application.ActivityLifecycleCallbacks $$delegate_0;{int $i$f$noOpDelegate = false;Class javaClass$iv = Application.ActivityLifecycleCallbacks.class;Object var10001 = Proxy.newProxyInstance(javaClass$iv.getClassLoader(), new Class[]{javaClass$iv}, DelegateObjectKt.getNo_op_invocationHandler());if (var10001 == null) {throw new NullPointerException("null cannot be cast to non-null type android.app.Application.ActivityLifecycleCallbacks");} else {this.$$delegate_0 = (Application.ActivityLifecycleCallbacks)var10001;}}public void onActivityCreated(@NonNull @NotNull Activity activity, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {Intrinsics.checkNotNullParameter(activity, "activity");this.$$delegate_0.onActivityCreated(activity, savedInstanceState);}public void onActivityDestroyed(@NonNull @NotNull Activity activity) {Intrinsics.checkNotNullParameter(activity, "activity");this.$$delegate_0.onActivityDestroyed(activity);}public void onActivityPaused(@NonNull @NotNull Activity activity) {Intrinsics.checkNotNullParameter(activity, "activity");this.$$delegate_0.onActivityPaused(activity);}public void onActivityResumed(@NonNull @NotNull Activity activity) {Intrinsics.checkNotNullParameter(activity, "activity");this.$$delegate_0.onActivityResumed(activity);}public void onActivitySaveInstanceState(@NonNull @NotNull Activity activity, @NonNull @NotNull Bundle outState) {Intrinsics.checkNotNullParameter(activity, "activity");Intrinsics.checkNotNullParameter(outState, "outState");this.$$delegate_0.onActivitySaveInstanceState(activity, outState);}public void onActivityStarted(@NonNull @NotNull Activity activity) {Intrinsics.checkNotNullParameter(activity, "activity");this.$$delegate_0.onActivityStarted(activity);}public void onActivityStopped(@NonNull @NotNull Activity activity) {Intrinsics.checkNotNullParameter(activity, "activity");this.$$delegate_0.onActivityStopped(activity);}});

现在已经将 ActivityLifecycleCallbacks 的匿名内部类对象委托给了 noOpDelegate 生成的代理对象。这样需要用到具体哪个方法时,只需要再次重写即可,例如文章最开始的例子可以变为

    val myActivityLifecycleCallbacks = object : Application.ActivityLifecycleCallbacks by noOpDelegate() {override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {TODO("Not yet implemented")}override fun onActivityDestroyed(activity: Activity) {TODO("Not yet implemented")}}

经过精简的代码可以使代码更加简洁,可以更好的聚焦业务实现

相关文章:

Kotlin 优雅的接口实现

1. 日常遇到的冗余的接口方法实现 日常开发中&#xff0c;经常会要实现接口&#xff0c;但是很多场景中&#xff0c;只需要用到其中一两个方法&#xff0c;例如 ActivityLifecycleCallbacks&#xff0c;它有很多个接口需要实现&#xff0c;但是很多时候我们只需要用到其中的一…...

新的面试题CSS

解释CSS Hack 一般来说是针对不同的浏览器写不同的CSS,就是 CSS Hack。 IE浏览器Hack一般又分为三种&#xff0c;条件Hack、属性级Hack、选择符Hack&#xff08;详细参考CSS文档&#xff1a;css文档&#xff09;。例如&#xff1a; // 1、条件Hack <!--[if IE]> <sty…...

DeepSeek R1打造本地化RAG知识库

本文将详细介绍如何使用Ollama、Deepseek R1大语音模型、Nomic-Embed-Text向量模型和AnythingLLM共同搭建一个本地的私有RAG知识库。 一. 准备工作 什么是RAG&#xff1f; RAG是一种结合了信息检索和大模型&#xff08;LLM&#xff09;的技术&#xff0c;在对抗大模型幻觉、…...

聚铭网络入围2025年度江苏省政府采购信息安全设备协议供货名单

近日&#xff0c;2025年度江苏省党政机关、事业单位及团体组织信息安全设备框架协议采购项目入围结果公布。聚铭网络凭借自身专业实力和技术优势脱颖而出&#xff0c;成功入围22个分包。 此次采购项目是江苏省政府采购领域级别最高、覆盖面最广的项目之一。从资格评选到后期材料…...

基于Flask的影视剧热度数据可视化分析系统的设计与实现

【FLask】基于Flask的影视剧热度数据可视化分析系统的设计与实现&#xff08;完整系统源码开发笔记详细部署教程&#xff09;✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 随着互联网技术的飞速发展&#xff0c;影视剧行业的数据量呈爆炸性增长&#x…...

【弹性计算】弹性计算的技术架构

弹性计算的技术架构 1.工作原理2.总体架构3.控制面4.数据面5.物理设施层 虽然弹性计算的产品种类越来越多&#xff0c;但不同产品的技术架构大同小异。下面以当前最主流的产品形态 —— 云服务器为例&#xff0c;探查其背后的技术秘密。 1.工作原理 云服务器通常以虚拟机的方…...

python-leetcode 31.K个一组翻转链表

题目&#xff1a; 给定链表的头节点head,每K个节点一组进行翻转&#xff0c;返回修改后的链表。 K是正整数&#xff0c;它的值小于等于链表的长度&#xff0c;如果节点总数不是K的整数组&#xff0c;那么将最后剩余的节点保持原有顺序。不能只改变节点内容的值&#xff0c;需…...

算法08-递归调用转为循环的通用方法

前导:问题引入 在Python中,递归调用过多会导致“递归深度过深”的错误,通常是因为递归没有正确终止条件或者递归层次太深。 这种错误通常会导致程序抛出 RecursionError 异常。 Python默认的递归深度限制大约是1000层(可以通过sys.getrecursionlimit()查看)。 修正方式…...

[创业之路-300]:进一步理解货币与金钱, 货币与货币政策

目录 一、货币 1.1 概述 1、货币的定义 2、货币的形态演变 3、货币的职能 4、货币的价值衡量 1.2 货币的分层 1、货币分层的目的与意义 2、货币分层的划分标准与层次 3、各国货币分层的实践 4、货币分层的影响与应用 1.3、M0、M1、M2变化对股市的影响 1、M0变化对…...

达梦:跟踪日志诊断

目录标题 参考连接**性能诊断&#xff1a;跟踪日志诊断****总结** 参考连接 性能诊断 -> 跟踪日志诊断 性能诊断&#xff1a;跟踪日志诊断 备份现有的日志配置文件 在修改文件之前&#xff0c;建议先备份原始文件&#xff0c;以防万一需要恢复。 cp /opt/dmdbms/dmdata/DA…...

Qwen2-VL 的重大省级,Qwen 发布新旗舰视觉语言模型 Qwen2.5-VL

Qwen2.5-VL 是 Qwen 的新旗舰视觉语言模型&#xff0c;也是上一代 Qwen2-VL 的重大飞跃。 Qwen2.5-VL主要特点 视觉理解事物&#xff1a;Qwen2.5-VL不仅能够熟练识别花、鸟、鱼、昆虫等常见物体&#xff0c;而且还能够分析图像中的文本、图表、图标、图形和布局。 代理性&…...

js考核第三题

题三&#xff1a;随机点名 要求&#xff1a; 分为上下两个部分&#xff0c;上方为显示区域&#xff0c;下方为控制区域。显示区域显示五十位群成员的学号和姓名&#xff0c;控制区域由开始和结束两个按钮 组成。点击开始按钮&#xff0c;显示区域里的内容开始滚动&#xff0c;…...

LabVIEW袜品压力测试系统

开发了一种基于LabVIEW开发的袜品压力测试系统。该系统利用LabVIEW并结合灵敏的传感器和高精度的处理模块&#xff0c;实现了对袜品压力的精确测量和分析。系统不同于传统的服装压力测试方法&#xff0c;为研究和评价袜子的舒适性提供了新的测试手段。 ​ 项目背景 该系统的…...

jsp页面跳转失败

今天解决一下jsp页面跳转失败的问题 在JavaWeb的学习过程中&#xff0c;编写了这样一段代码&#xff1a; <html> <body> <h2>Hello World!</h2><%--这里提交的路径&#xff0c;需要寻找到项目的路径--%> <%--${pageContext.request.context…...

1.推荐算法基本概念

推荐算法是一个非常重要且广泛应用的领域&#xff0c;特别是在电子商务、社交媒体、内容推荐等领域。第一课我们将介绍推荐算法的基本概念和分类&#xff0c;并简单讲解两种常见的推荐算法&#xff1a;协同过滤和基于内容的推荐。 推荐算法的基本概念 推荐系统的目标是根据用…...

Java 大视界 -- 大数据伦理与法律:Java 技术在合规中的作用与挑战(87)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

【ISO 14229-1:2023 UDS诊断全量测试用例清单系列:第十五节】

ISO 14229-1:2023 UDS诊断服务测试用例全解析&#xff08;RoutineControl_0x31服务&#xff09; 作者&#xff1a;车端域控测试工程师 更新日期&#xff1a;2025年02月14日 关键词&#xff1a;UDS协议、0x31服务、例程控制、ISO 14229-1:2023、ECU测试 一、服务功能概述 0x31服…...

【深度强化学习】策略梯度算法:REINFORCE

策略梯度 强化学习算法进阶 Q-learning、DQN 及 DQN 改进算法都是基于价值&#xff08;value-based&#xff09;的方法&#xff0c;其中 Q-learning 是处理有限状态的算法&#xff0c;而 DQN 可以用来解决连续状态的问题。在强化学习中&#xff0c;除了基于值函数的方法&#…...

手机用流量怎样设置代理ip?

互联网各领域资料分享专区(不定期更新)&#xff1a; Sheet...

CI/CD部署打包方法

项目目前部署方式&#xff1a; 各地区服务器打包同一个runner&#xff08;需要互相排队&#xff0c;不并发&#xff09;各地区客户端可以并发打包&#xff0c;同个地区客户端打多个包需要排队 部署方法 下载gitlab-runner&#xff1a; https://docs.gitlab.com/runner/insta…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

Qemu arm操作系统开发环境

使用qemu虚拟arm硬件比较合适。 步骤如下&#xff1a; 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载&#xff0c;下载地址&#xff1a;https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...

命令行关闭Windows防火墙

命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)​方法二:CMD命令…...

Springboot 高校报修与互助平台小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;高校报修与互助平台小程序被用户普遍使用&#xff0c;为…...