随笔记录

2025-9-19 评论(0) 分类:生活 Tags:

最近这段时间因为会去看一些视频,分辨率有点低,所以眼镜有点难受,一查散光加深了,真是有点难受,希望能够以后做什么事情都要把健康放在第一位,马上国庆了,想回家去看看放松放松,对眼睛也好一些。

老家在修房子,妈妈每天很早就回家规整房子的事情,妈妈一直以来跟我说她睡眠不好,还是希望能狗让她能够意识到睡眠是一件很重要的事情,还有一个事情就是因为我没有结婚让她操心,希望她能够想开,或者我早点结婚让她少一桩心事?都挺难的,一步步把自己的事情做好吧。

今年夏天没有带父母出去旅游,希望明年能实现这个愿望。

最近常常思考佛家说的“众生皆苦”这个词。理论上,我们从来到这个世界开始,就是在dying的路上了,只是时间问题。这么一想,就连今天看到一个不喜欢的人,我想到在未来的某一天,他也要独自面对疾病和死亡,出于本能我都会对他抱以同情,希望他能挺过去,从这个视角再去看身边的很多人,会多一点宽容和善意,因为有限的时间里因为各种因缘际会我们产生了交集,我都希望你们能过得更甜一些。
因为,众生皆苦。

前几天晚上做了一个梦,恍然回到刚毕业在B站工作的时候。一位同事因加班猝然离世,孩子才刚出生不久。周会上,组里一位女同学哭得特别伤心。那时我还年轻,总觉得生死之事离自己很远,虽感到难过,却未能真正体会和共情那份沉重。

如今三十岁了,越来越懂得生命的脆弱,众生皆苦。昨晚偶然在小宇宙上听到一位播客女主播的声音,像极了当年那位女同学,记得她叫小只,突然想起这段往事。时光模糊了许多细节,却让某些感受愈发清晰。

基于镜像反射组件动态化实践

2025-5-5 评论(0) 分类:作品 Tags:

引言:反射困境

在Runtime动态化开发中,我们会遇到比如最简单一个log打印

fun Main() {    Log.i("test","打印")}

对应的DSL

[应用层]
   └── Test类

[编译层]
   └── 注解处理器
       ├── 导入指令解析
       │   ├── android.util.Log
       ├── 方法声明解析
       │   └── Main方法 (包含日志打印)
       └── 元数据处理
[运行时层]
   └── ComposeComponentRegistry
       ├── 组件注册表
       ├── 类型安全构建器
       └── 参数转换器

这种最简单的做法就是反射直接调用。这种第一个是运行时加载,对性能有影响,其次经常面临这样的场景:需要根据服务端下发的配置动态渲染UI组件。以布局属性Alignment.CenterHorizontally为例,传统反射方案会尝试:

然而这种常规反射手段在Compose框架中频繁遭遇ExceptionInInitializerError,其根本原因在于:

  1. 接口常量陷阱:Alignment本质是包含静态常量的接口(interface),其初始化机制与普通类不同
  2. 类加载死锁:Compose内部类之间存在复杂的初始化依赖链
  3. 混淆干扰:ProGuard规则可能导致反射路径断裂
  4. 性能损耗:传统反射API的调用效率难以满足我们对高频渲染需求

本文提出一种基于编译时反射代码生成的镜像反射方案,借鉴Dart的reflectable库思想,构建编译期静态反射体系:,通过脚本精简实现静态化的类型安全反射,在保持Compose组件特性的同时,实现高性能的运行时动态化能力。

镜像API允许程序反思自己。从历史上看,它起源于SELF,就像许多其他伟大的虚拟机技术一样,而我们Runtime机制本质上其实就是在做一个虚拟机的事情。如果你想了解更多关于镜像及其在其他系统中的作用,可以看Gilad Bracha的文章并跟随链接。

镜像的存在是为了回答反射性的问题,比如。”给定对象的类型是什么?”、”它有哪些字段/方法?”、”字段的类型是什么?”、”给定方法的参数的类型是什么?”以及执行反射性动作,如 “从该对象获取这个字段的值!”和 “在该对象上调用这个方法!”

一、技术方案全景图

1.1 架构分层

[应用层]
   └── @Reflectable注解标记

[编译层]
   └── KSP注解处理器
       ├── 元数据解析
       ├── 反射代码生成
       └── 混淆规则生成

[运行时层]
   └── ComposeComponentRegistry
       ├── 组件注册表
       ├── 类型安全构建器
       └── 参数转换器
@Reflectable
class CustomCard(val title: String)
public class CustomCard_ReflectProxy : ComponentProxy {
    override fun createInstance(args: Map<String, Any?>): Any {
        return CustomCard(
            title = args["title"] as String
        )
    }

    override val descriptor = ComponentDescriptor(
        name = "CustomCard",
        params = listOf(
            ParameterDescriptor("title", String::class)
        )
    )
}
组件注册表
object ComposeComponentRegistry {
    private val registry = ConcurrentHashMap<String, ComponentProxy>()

    fun register(proxy: ComponentProxy) {
        registry[proxy.descriptor.name] = proxy
    }

    fun createComponent(name: String, args: Map<String, Any?>): Any {
        return registry[name]?.createInstance(args)
            ?: throw ComponentNotFoundException(name)
    }
}
fun process(reflectableElements: List<KSClassDeclaration>) {
    reflectableElements.forEach { cls ->
        // 1. 元数据提取
        val properties = cls.getAllProperties()
        val functions = cls.getDeclaredFunctions()

        // 2. 校验约束
        validateReflectableConstraints(cls)

        // 3. 生成桥接类
        generateBridgeClass(cls, properties, functions)

        // 4. 生成映射规则
        generateProguardRules(cls)
    }
}

1.2 核心优势

  • 编译时确定性:所有反射逻辑在编译期展开为直接调用
  • 零反射开销:生成的代码与手写调用等效
  • 混淆免疫:自动生成匹配的keep规则

二、未来演进方向

  1. 跨模块热更新:支持动态加载组件镜像
  2. 动态生成:目前还是依赖于手动添加,一旦有API更细很容易遗漏,可以通过import的依赖信息自动导入,生成reflect中间类。
  3. IDE动态支持自测case:庞大的反射类需要更为细致的自测case来支持,这里可以使用通过大模型帮忙生成自测case时一个不错的选择。

最后

通过镜像反射技术的深度应用,我们成功将Compose组件的动态加载性能提升了一个数量级,同时解决了长期困扰Aether的加载系统类的导致的性能损耗的问题和健壮性问题。该方案在基于Runtime虚拟机场景落地,也为Aether动态化开辟了新的可能性边界。

我的第一篇blog

2025-4-29 评论(0) 分类:生活 Tags:

很开心能第一次在这里写blog,以前偶尔会在微信公众号去写一些,但会被身边熟人看到,希望能有自己的站点记录生活、记录青春,记录成长,终于在今天达成,希望能够坚持写下去。