乐于分享
好东西不私藏

让 AI 真懂 Jetpack Compose:aldefy/compose-skill 实用评测

让 AI 真懂 Jetpack Compose:aldefy/compose-skill 实用评测
给 AI 编码工具装一份 Compose 领域知识包,到底有多大用?一个 Android 工程师视角的实用评测。

图片制作:Nano Banana 2

本文基于 aldefy/compose-skill 仓库 master 分支 f5863ec commit(v2.1.2 之后)的内容。

AI 写 Compose 的几个经典翻车现场

先讲几个 Android 工程师大概率亲身遇到过的场景。

场景一:用了已经被弃用的 API。 你让 AI 给 LazyColumn 的 item 加一个排序动画,AI 熟练地给你写:

LazyColumn {    items(items, key = { it.id }) { item ->        ItemRow(item.nameModifier.animateItemPlacement())    }}

代码能跑,编译器也只是个 deprecation 警告。但 animateItemPlacement() 从 Compose 1.7 开始就被 animateItem() 取代了——新 API 能给你 placement、appearance、disappearance 三条独立的动画规格,旧 API 只有 placement 一条。AI 完全不提这事,因为它脑子里的”Compose 知识”是训练时的快照,没更新。

场景二:路由还在用字符串。 你让 AI 给你搭一个 NavHost,它甩给你 composable("details/{id}") + backStackEntry.arguments?.getString("id") 这一套。Navigation 2.8+ 已经有了类型安全的 @Serializable 路由类,用 toRoute() 就能拿到对象,再也没有字符串拼错导致的运行时崩溃。AI 不知道这个升级,或者说知道但没优先推荐。

场景三:remember 不加 key,旋转一下就出问题。 一个典型的 shimmer placeholder 实现:

val config = LocalConfiguration.currentval screenHeightDp = config.screenHeightDpval shimmerCount = remember { (screenHeightDp / itemHeightDp).toInt() }

初看没毛病。但旋转手机、或者折叠屏展开之后,screenHeightDp 变了,shimmerCount 还是旧值——因为 remember {} 不加 key 只会在第一次 composition 算一次。remember(screenHeightDp) 才是正确的写法。这种 bug 不会直接崩,但会让 UI 在某些设备上表现异常,而且很难复现。

这三个坑都不是”AI 不够聪明”,而是AI 不读代码,凭印象答。它的 Compose 知识来自预训练语料里的博客、Stack Overflow、旧版文档——这些内容跟不上 androidx/androidx 仓库主分支的节奏,也很少涉及”旋转手机时会怎样”这种边角案例。

给 AI 配一份实时对齐 androidx 源码的领域知识包,也许能治这个病。这就是 aldefy/compose-skill 要做的事。

这个 Skill 包主张什么

aldefy/compose-skill(仓库名,Skill 本身叫 compose-expert)是一个专门喂给 AI 编码工具的 Jetpack Compose / Compose Multiplatform 领域知识包。当前版本 v2.1.2,MIT 协议。

它的结构是这样的:

skills/compose-expert/├── SKILL.md                         入口 + 调度表└── references/    ├── state-management.md          状态和生命周期    ├── modifiers.md                 modifier 顺序    ├── animation.md                 动画配方    ├── ...(共 22 份 reference)    └── source-code/                 真实 androidx / CMP 源码摘录        ├── runtime-source.md        Composer / Recomposer / State        ├── foundation-source.md     LazyList / Clickable / Pager        ├── material3-source.md      M3 全套组件        └── ...(共 6 份源码文件)

两层结构是它的核心设计:

  • 第一层:guidance
    22 份 references/*.md,每份讲一个具体主题——什么时候用 derivedStateOfModifier 应该按什么顺序排、LaunchedEffect 的 key 怎么给、CMP 里哪些 API 只在 Android 上有。AI 日常读这一层。
  • 第二层:source code receipts
    6 份从 androidx/androidx 主分支和 JetBrains/compose-multiplatform-core 主分支原样摘下来的 Kotlin 源码——Clickable.ktComposer.ktLazyList.ktMaterialTheme.kt 这些。加起来大约 5.5 万行代码。只有当 AI 需要确认某个细节到底是怎么实现的,才下钻到这一层。

这种”guidance + source”的两层设计,背后的核心理念是它自己在 README 里反复强调的一句话:“backed by real source code, not vibes”(源码作证据,不凭感觉)。翻译成大白话:让 AI 查字典,而不是凭印象回答

调度入口是 SKILL.md,它干两件事:一是声明一堆触发关键词(@ComposableLazyColumnNavHostModifiercommonMain 等等),让 AI 工具知道什么时候激活这份 skill;二是维护一张”主题 → reference 文件”的映射表,AI 根据用户问的问题去拿对应的 reference。比如用户问”我的 LazyColumn 滚起来卡”,它就会同时调 lists-scrolling.md 和 performance.md

它还有一个”PR review mode”——当用户输入里带 GitHub PR URL 或者说”review this PR”时,AI 会换一套流程:先把整个 diff 和全文件拉下来,扫项目的 .editorconfig 和 detekt 配置,然后按一份内置 checklist 给你本地报告(不会自动发回 GitHub)。这算是个附加功能,不是 skill 的主线。

兼容性层面,同一份 markdown 被 8 个 AI 编码工具共用:Claude Code、Codex CLI、Gemini CLI、Google Antigravity、Cursor、GitHub Copilot、Windsurf、Amazon Q Developer。每个工具的集成方式略有不同(Claude Code 放 ~/.claude/skills/、Cursor 用 .cursor/rules/*.mdc、Codex 用 AGENTS.md 指向 SKILL.md 等等),但读的是同一份内容。换工具不用重学。

接下来按主题讲这 22 份 reference 分别在治什么病。

按主题讲:22 份 reference 分别治什么病

22 份文件不逐个点名,按 AI 翻车的”病种”分成 9 组看。每组前先一句话说清楚这组治什么。

组 1:状态与生命周期

治的病:AI 把 remember { mutableStateOf() } 当万金油;LaunchedEffect 的 key 乱给;不清楚什么该传参、什么该走 CompositionLocal

这组三份:state-management.mdside-effects.mdcomposition-locals.md

状态管理这块是 Compose 里最容易写错、也最难 debug 的一块。AI 的典型毛病是:不管什么场景都甩 remember { mutableStateOf() }——该用 derivedStateOf 推导值的地方也用,该 rememberSaveable 在进程死亡后恢复的地方也用,该把状态提升(hoist)到父组件的地方也不提升。state-management.md 把这几个 API 的适用场景列清楚,附带 snapshotFlow 的用法。

副作用那一份讲的是  LaunchedEffect  /  DisposableEffect  /  SideEffect / rememberCoroutineScope 怎么选、key 怎么给。“key 错了不会崩,但会静默地多跑一次或少跑一次”是 Compose 里最阴的 bug 之一,这份 reference 就是在防这个。

CompositionLocal 那份回答一个经典问题:是该把东西当参数一路传下去,还是扔 CompositionLocal 里让所有子组件都能读?新手 AI 经常一股脑用 CompositionLocal,把组件耦合搞得一塌糊涂。这份给了一个明确的决策树。

组 2:视图与布局

治的病:composable 切分颗粒度没谱;modifier 顺序错;LazyColumn 忘给 key {} 导致无谓重组。

这组三份:view-composition.mdmodifiers.mdlists-scrolling.md

Modifier 顺序是典型”AI 答对了就是走运”的知识点。Modifier.padding(16.dp).background(Color.Red) 和 Modifier.background(Color.Red).padding(16.dp) 出来的视觉效果完全不同——前者背景包着 padding 之外的内容,后者背景填满整个 Box。modifiers.md 把这些顺序规则、clickable 的热区问题、clip 和 background 的组合都写明白了,顺带讲了从 Modifier.composed 迁移到 Modifier.Node 的新 API。

lists-scrolling.md 治的最大的病是忘给 key {}——不给 key 的 LazyColumn,item 一移动位置就会整块重新组合。这份还讲了 contentType 怎么用(让 LazyList 复用 ViewHolder 一样的东西)、什么时候用 LazyVerticalGrid 而不是嵌套的 Column

view-composition.md 讲的是组合的颗粒度:什么时候该拆成子 composable、@Preview 怎么摆、slot API 怎么设计。AI 在这块常犯的是”全写一个大 composable”或者”拆得太碎导致每个小 composable 只用一次”。

组 3:动效与主题

治的病:动画 API 太多分不清(animate*AsState vs updateTransition vs AnimatedVisibility);M3 Motion 的 duration 和 easing token 记不全;Style {} 这种 experimental API 的坑不知道。

这组五份:animation.mdtheming-material3.mdmaterial3-motion.mdatomic-design.mdstyles-experimental.md

动画这组内容最多,因为 Compose 里动画 API 矩阵确实复杂。animation.md 包括了 9 条常见动画配方(shimmer、swipe-to-dismiss、共享元素转场等等),还讲了怎么把 Figma 里的贝塞尔曲线映射到 Compose 的 easing。

material3-motion.md 单独拎出来,因为 M3 把动效也做成了 token 系统——MaterialTheme.motionScheme 下的 defaultSpatialSpec() / defaultEffectsSpec() 是什么、什么时候用 fastSpatialSpec()、M3 的 duration token(DurationShort1–4 / DurationMedium1–4 / DurationLong1–4 / DurationExtraLong1–4)分别是多少毫秒。这些数字 AI 几乎不可能记得全,真去问它大概率编一个。

atomic-design.md 比较有意思——它把 Brad Frost 那套 Atomic Design(tokens / atoms / molecules / organisms / templates)映射到 Compose 的层级里,给出一套组件库的搭法:token 走 MaterialTheme + 自定义 CompositionLocal,atom 要有 slot + modifier 参数,organism 不能直接用 Text() 必须走 atom。对做设计系统的团队挺实用。

styles-experimental.md 讲的是 Foundation 1.11.0-alpha06 里新出的 Style {} 实验性 API——声明式地把一个组件的所有交互状态(pressed、selected、disabled)写在一个块里,让框架自己插值动画。这块因为还 experimental,坑特别多,有专门一份 reference 盯着。

组 4:导航

治的病:AI 还在推荐字符串路由,而不是 Navigation 2.8+ 的类型安全路由。

这组就一份:navigation.md

前面”翻车现场”已经提过了——字符串路由会让你运行时才发现路径拼错或者参数类型搞错。类型安全路由要求你用 @Serializable 声明路由类,配合 kotlinx-serialization 插件。这份 reference 把新 API 的写法、深链(deep link)、共享元素转场(shared element transitions)、回退栈管理都列全了。

组 5:性能 / 崩溃 / 无障碍 / 遗留 API

治的病:不加 @Stable / @Immutable 导致无脑重组;不知道生产环境那几个经典崩溃模式;semantics 乱写;还在用已移除的 API。

这组四份:performance.mdproduction-crash-playbook.mdaccessibility.mddeprecated-patterns.md

performance.md 讲的是让 Compose 编译器帮你跳过重组(skipping)需要什么条件——参数必须稳定(stable),不稳定的参数(比如 List<T> 这种接口类型)会让整个 composable 每次都重组。还讲了延迟读取(deferred read)、baseline profile、benchmark 怎么跑。

production-crash-playbook.md 是我觉得这个项目最值回票价的一份。它不讲理论,只讲生产环境里真实发生过的崩溃模式——remember 不加 configuration key 导致旋转后 stale、indexOf() 在 items {} 里用导致 O(n²) 加 IndexOutOfBoundsExceptionCanvas 初次 composition 时 size = Size.Zero,派生运算(比如 360f / size.width 算角度)产生 Infinity / NaN 塞给 Skia 渲染管线才撞崩,等等。每个都是根因 + 错误代码 + 修复代码 + 一条规则。这些是 AI 完全没机会在训练语料里学到的——没人会把自家 App 的 crashlog 发公开。

accessibility.md 讲 semantics、content description、traversal order、触控目标最小尺寸、TalkBack 测试。AI 给出的 Compose 代码里无障碍基本是欠的。

deprecated-patterns.md 是一张”迁移表”:accompanist-systemuicontroller 换成 enableEdgeToEdge()accompanist-pager 换成原生 HorizontalPageranimateItemPlacement() 换成 animateItem()Modifier.composed 换成 Modifier.Node。AI 特别需要这个表,因为它的知识快照里经常混着已经过时的写法。

组 6:跨平台与特殊平台

治的病:把 Android-only 的 API (R.drawable.xxx  /  LocalContext / BackHandler)扔进 commonMain;TV 上不知道怎么处理 D-pad 焦点;Web/WASM 的 canvas 限制不知道。

这组三份:multiplatform.mdplatform-specifics.mdtv-compose.md

如果你的项目不是 CMP、不是 TV、也不打算上 iOS,这组可以跳过。但如果是,这组非常关键——因为 AI 对 CMP 和 TV Compose 的知识特别稀薄。

multiplatform.md 讲 expect / actual 怎么用、资源系统 Res.drawable / Res.string / Res.font 怎么组织、从纯 Android 迁移到 CMP 的路径。最常治的病是 AI 把 R.font.xxx 塞进 commonMain——这东西只在 Android sourceset 里有。

platform-specifics.md 分 Desktop、iOS、Web/WASM 三块:Desktop 的 Window / Tray / MenuBar、iOS 的 UIKitView 和各种坑(键盘处理、scroll 手势冲突)、Web/WASM 的 canvas 限制。

tv-compose.md 相当厚——Android TV 用的是专门的 androidx.tv:tv-material 而不是普通 material3,Surface、Card、Carousel、NavigationDrawer、TabRow 全是 TV 专用版本(带焦点指示),D-pad 导航和 10-foot UI 的间距规则都要特别处理。AI 在 TV 这块翻车率尤其高,因为训练语料里 TV 开发的文章少。

组 7:设计到代码

治的病:从 Figma 翻译代码时逐节点硬搬,不会用 M3 语义组件;spacing 和 padding 的归属搞错。

这组一份:design-to-compose.md

它讲的是”看图写代码”的方法论:先把设计分解成 composable 树(一套 5 步方法)、Figma 的属性怎么映射到 Compose 参数(比如 Figma 的 auto-layout 对应 Row / Column 的 Arrangement + Alignment)、spacing 应该归谁拥有(父给还是子拿)、modifier 顺序怎么排。给设计稿写 Compose 代码时这份特别有用,比 AI 凭空 hallucinate 出一堆 Box 套 Box 强得多。

组 8:协作工作流

治的病:这组不治具体 bug,改善 AI 跟你协作的流程。

这组两份:auto-init.mdpr-review.md

auto-init.md 是一个自动激活机制——AI 在会话开始时扫一眼当前目录的 build.gradle.kts / libs.versions.toml,如果看到 compose 或 androidx.compose 这些关键字就自动把 skill 激活;如果 Gradle 没检测到就 fallback 去扫 .kt 文件找 @Composable 注解。检测到就打一行”Compose project detected — compose-expert skill active”,没检测到就静默等关键词触发。好处是你不用在 prompt 里反复提醒 AI “记得看 compose skill”。

pr-review.md 前面提过——它定义了一整套 Review Mode 流程:拉 diff → 拉完整文件(因为 diff 里看不到 modifier 链的全貌)→ 扫项目的 lint 配置和 3-5 个非 diff 里的 @Composable 文件推断团队约定 → 按 6 类 checklist(modifier 卫生、重组 stability/skipping、M3 动效、CMP 兼容、列表与 key、原子设计含命名规则)打分 → 输出本地报告。有意思的是它强调”推断团队约定”——不按外部风格指南打分,按你团队现有代码的风格打分。

组 9:源码证据层

治的病:AI 需要确认某个 Compose 内部实现细节时,不用凭印象,直接读原汁原味的 androidx 源码。

这组六份:runtime-source.mdui-source.mdfoundation-source.mdmaterial3-source.mdnavigation-source.mdcmp-source.md

这层下一节展开讲——因为它的角色和前 8 组不一样,它不是”告诉 AI 怎么做”的指导,而是”让 AI 有地方查”的字典。

源码证据层:为什么要单独一层

6 份源码摘录加起来大概 5.5 万行代码。都是从 androidx/androidx 的 androidx-main 分支和 JetBrains/compose-multiplatform-core 的 jb-main 分支原样扒下来的 Kotlin 源码,外面包一层 Markdown,附上每个类的原始文件路径。

每一份大致覆盖:

  • runtime-source.md
    Composer.ktRecomposer.ktState.ktEffects.ktCompositionLocal.ktRemember.ktSlotTable.ktSnapshot.kt——Compose 运行时的核心,remember 和 State 到底怎么工作的。
  • ui-source.md
    Modifier.ktLayout.ktLayoutNode.ktModifierNodeElement.ktDrawModifier.kt 等——modifier 系统和布局系统的内部实现。
  • foundation-source.md
    LazyList.ktLazyGrid.ktBasicTextField.ktClickable.ktScrollable.ktPager.kt——所有常用组件的真实实现。
  • material3-source.md
    MaterialTheme.ktColorScheme.ktButton.ktScaffold.ktTextField.ktNavigationBar.kt 等——M3 组件全套。这份最大,接近 2 万行。
  • navigation-source.md
    NavHost.ktComposeNavigator.ktNavGraphBuilder.ktDialogNavigator.kt
  • cmp-source.md
    CMP 的 Window.kt(Desktop)、ComposeUIViewController.kt(iOS)、UIKitView.ktComposeViewport.kt(Web)、ResourceReader.kt

为什么要把源码单独作为一层?因为 guidance 和源码回答两种不同的问题。

Guidance 回答”我应该怎么做”——derivedStateOf 什么时候该用、LazyColumn 的 key 怎么给、modifier 顺序怎么排。这是结论性的、经过提炼的、带示例的。AI 大部分时候读这一层就够。

源码回答”它实际上是怎么实现的”——LazyList 到底怎么判断 item 可以复用?Clickable 的 ripple 是怎么跟 InteractionSource 联动的?MutableState 怎么触发重组?这是细节性的、未经提炼的、没有示例的。只有在 AI 遇到 guidance 回答不了的问题(比如”这个 API 的某个参数到底做了什么”),或者用户直接要求”show me the actual implementation”的时候,才下钻到这一层。

用一个类比:guidance 是教材,源码是开卷考试时发的原版资料。教材足以应付大多数题,遇到超纲题可以翻原版资料查。把两层分开,AI 就不会每次都把几万行源码塞进上下文——那样的话根本没有 context 留给你的实际代码。

实战工作流:skill 怎么和 Android 工具链接上

前面讲的是 skill 里装了什么。这节讲装了之后在日常开发里具体怎么”用起来”——三个最能体现价值的工作流。

场景一:让 AI 审你现在的代码

对 Android 工程师来说最高频的用法其实不是让 AI 写新代码,是让它审已有代码。Skill 里一份 pr-review.md 专门定义了 Review Mode——两种触发方式:

  • 贴 GitHub PR URL,它会用 gh pr diff 拉 diff
  • 本地直接说 “review this code” / “check this code” / “what’s wrong with this”,配上你要审的文件路径

Review Mode 启动后会跳出正常的”帮你写代码”流程,换一套审计流:

  1. 完整文件而不是只看 diff——modifier 链跨行时 diff 里看不全
  2. 扫项目的 .editorconfig / ktlint / detekt 配置
  3. 找 3-5 个不在 diff 里的 @Composable 文件推断团队约定,按你团队自己的风格打分,不强推外部 style guide
  4. 按 6 类 checklist 审:modifier 卫生、重组(stability / skipping)、M3 动效、CMP 兼容、列表与 key、原子设计(含命名规则)
  5. 输出本地报告,不自动发回 GitHub

最值钱的是”推断团队约定”这步。AI 做 code review 最大的毛病是按它想象的最佳实践打分,给一堆和你团队习惯拧着的建议。Review Mode 显式读你已有代码再评判一致性,结论更能用。

附带的好处是:你可以在 prompt 里显式要求它对照 production-crash-playbook.md 做预防性检查(这不是 Review Mode 的默认行为,但加一句就行)——这样它会把 playbook 里的生产崩溃模式也纳入检查范围,把通用 lint 看不出来的 Compose 专属坑在合入前就提示出来(具体有哪些模式,看下面场景二)。

具体怎么发 prompt:

review this code: app/src/main/java/com/example/chat/ui/MessageScreen.kt重点帮我看:- state hoisting 合不合理、有没有把 ViewModel 的 state 乱摊到 UI 层- Modifier 顺序有没有经典错(尤其 clickable / padding / size 的排法)- 有没有命中 production-crash-playbook 里的崩溃模式- 和项目里其他 Compose 文件风格一致不一致

AI 的响应会长这样(基于虚构的 MessageScreen.kt):

Compose Review Report: MessageScreen.kt

== Modifier 卫生 ==

✗ L42:Row(Modifier.fillMaxWidth().padding(16.dp).clickable { ... })——clickable 应在 padding 之前,否则 padding 区域不响应点击。你项目里其他文件都是先 clickable 再 padding,参考 HomeScreen.kt:78ChatListScreen.kt:52

== 重组(stability / skipping)==

⚠ MessageScreen 参数 messages: List<Message> 是接口类型(unstable),会让整个 composable 无法 skippable,父组件重组时 MessageScreen 会无条件跟着重组。建议改 ImmutableList<Message>kotlinx-collections-immutable)或给 Message 加 @Immutable

== 生产崩溃模式 ==

✗ L67:messages.indexOf(message) 写在 items {} 里——命中 playbook 模式 #2。当 messages 里对象被重建(新的网络响应映射成新实例),indexOf 用结构相等找不到、返回 -1,拿去当索引就抛 IndexOutOfBoundsException。改成 itemsIndexed(messages, key = { _, m -> m.id }) 拿 index。

== 团队约定推断 ==

参考 ChatListScreen.ktHomeScreen.ktSettingsScreen.kt 三份文件:你们习惯 modifier 链一行一个、单 slot composable 用 trailing lambda。本文件 L42 的 modifier 链是一行到底,和团队约定不一致(非致命)。

(其他类别 M3 动效 / CMP 兼容 / 列表与 key / 原子设计:没发现问题。)

注意这份报告里每一条都带了行号理由——这是 skill 里 pr-review.md 显式要求的格式,不靠运气。以及”团队约定推断”那段会明确说它参考了哪几个现有文件——让你知道它的结论基于什么证据,不是凭空标准打分。

但要清楚它的边界:静态检查 + 模式对照,不跑你的代码。适合做一轮 pre-review 粗筛——很多明显的 modifier 错、skipping 问题、playbook 模式它会稳定地捕到;但涉及业务逻辑、并发正确性、跨 composable 的状态流动,它看不出来。不代替真正的 code review,只是让你在 PR 评审前先过一道”送分题”。

场景二:崩溃栈配 production-crash-playbook 做根因分析

这是 skill 最能帮你省时间的一个场景——线上或测试机跑你的 App 崩了,你要快速判断是 Compose 的什么模式翻了车。

先用 adb 把崩溃栈抓下来:

adb logcat -d -b crash# 或者锁定运行时崩溃adb logcat -s AndroidRuntime

把 stack 贴给 Claude Code,让它对照 production-crash-playbook.md 判断——这份 reference 按”根因 + 错误代码 + 修复代码 + 预防规则”四件套列了 6 种 Compose 专属的生产崩溃模式(文末还有一张 Quick Reference 把更多崩溃模式汇总到一起)。

比如你可以这样发:

这是线上用户反馈的崩溃 stack,对照 production-crash-playbook.md看看命中哪种模式,再给修复方案(附上相关文件位置):FATAL EXCEPTION: mainjava.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 50    at com.example.chatapp.ui.MessageList$lambda$3.invoke(MessageList.kt:42)    at androidx.compose.foundation.lazy.LazyListIntervalContent...

AI 的响应会是:“命中 playbook 模式 #2——indexOf() 在 items {} 里用。你在 MessageList.kt:42 大概率写了 messages.indexOf(message),当 messages 里的对象被重建(比如新的网络响应映射成新实例),indexOf 用结构相等找不到,返回 -1 再当索引用就抛 IndexOutOfBoundsException。修复:改成 itemsIndexed(messages, key = { _, m -> m.id }) 直接拿 index。”

playbook 里其他模式举例:

  • LazyColumn 的 key 重复
    :后端 WebSocket 重连后推送了 ID 相同的消息,items(messages, key = { it.id }) 一旦撞上两个一样的 id,就抛 IllegalArgumentException: Key X was already used。playbook 的修复是给数据类加一个不参与 equals/hashCode 的 dedupIndex 字段,放进 key 里保证唯一
  • 多 section LazyColumn 的 key 跨 section 冲突
    :同一条消息同时出现在 “pinned” 和 “live” 两个 items {} 里、都用 it.id 做 key——两个 section 里同一 id 就撞。修复是在 key 里加 section 类型前缀(例如 "pinned_${it.id}"
  • derivedStateOf 只暴露集合的 size
    derivedStateOf { allItems.count { 过滤条件 } } 只推出一个 count,然后 items(count) 块里用另一个 .filter { ... } 重算集合——count 和实际集合在不同 frame 算的,一旦错位就索引越界抛 IndexOutOfBoundsException。修复是让 derivedStateOf 直接推出整份过滤后的 list,count 和访问用同一份
  • Canvas 初次 composition 收到 Size.Zero
    drawCircle(radius = 0f) 单独不崩,但派生运算(比如 360f / size.width 算角度、x / size.width 归一化坐标)会算出 Infinity / NaN,再塞给 Skia 才真撞渲染管线

这些模式通用 AI 基本看不出。原因朴素——没人会把自家 App 的 crashlog 公开发文章,这类知识在训练语料里就是缺的。Skill 相当于把一份”Compose 生产事故集”常驻在 AI 手边。

让 AI 自己跑 adb logcat 要先放行。Claude Code 默认每跑一次 shell 命令都会问”可以跑吗”,频繁跑 adb 会烦,可以在项目的 .claude/settings.json 里 allowlist:

{  "permissions": {    "allow": [      "Bash(adb *)",      "Bash(./gradlew *)"    ]  }}

这样 AI 可以自己抓栈、自己查 playbook、自己给根因判断,你只需要决定采纳不采纳它的修复建议。

场景三:开 Compose Compiler Reports 配 performance.md 解读

这是 skill 和 Android 工具链组合里最出彩的一个场景——性能优化。

先在 app/build.gradle.kts 里加一段,打开编译器报告生成(Kotlin 2.0+ 的现代 DSL 写法):

composeCompiler {    reportsDestination = layout.buildDirectory.dir("compose_compiler")    metricsDestination = layout.buildDirectory.dir("compose_compiler")}
然后跑 release 构建——Compose Compiler Reports 官方推荐在 release 上看,debug 构建的 stability 判定和 release 会有差异,性能优化以 release 为准:
./gradlew :app:assembleRelease

Gradle 会在 app/build/compose_compiler/ 下生成几份报告,主要关心两份:

  • <module>_release-composables.txt
    每个 @Composable 函数的状态——是不是 restartableskippable,每个参数是 stable 还是 unstable
  • <module>_release-classes.txt
    每个 class 的 stability——stable / unstable / runtime

报告长这样:

// app_release-composables.txt 摘选restartable skippable funMessageRow(  unstable message: Message  stable modifierModifier? = @static Companion)restartable funMessageList(  unstable messages: List<Message>  stable modifierModifier? = @static Companion  stable onMessageClick: Function1<MessageUnit>)// app_release-classes.txt 摘选unstable class Message {  stable val id: String  stable val text: String  unstable val reactions: List<Reaction>  <runtime stability> = Unstable}
纯看这份报告会劝退新手——它只告诉你”这个参数是 unstable”,不告诉你该怎么办。纯读 performance.md 又只有规则不看你项目。两个合起来才通。把报告片段扔给 Claude Code:
这是 compose compiler reports 的输出,对照 performance.md 分析一下哪些 composable 可以优化成 skippable、哪些 class 需要改稳定,按收益大小排个优先级:<粘贴 composables.txt 和 classes.txt 的相关片段>

AI 的响应会是这样(基于上面的报告片段):

优先级 1(收益最大):MessageList 完全不 skippable。 参数 messages: List<Message> 是接口类型,Compose 编译器无法证明它不可变,所以每次父 composable 重组都会让 MessageList 跟着重组,哪怕 messages 引用没变。这个 composable 通常在顶层,它不 skippable 会拖垮一整片子树。

优先级 2:Message class 本身 unstable。 因为 reactions: List<Reaction> 是接口类型,让整个 class 被判定为 Unstable。这反过来导致 MessageRow 的 message 参数标 unstable——虽然 MessageRow 是 skippable,但 skip 条件变成了”message 引用必须 === 上次的那个”,稍微不注意就 skip 不了。

修复建议(按实施成本从低到高):

  1. 给 Message 加 @Immutable 注解——如果你能保证 reactions 实际不会被修改,这是成本最低的 opt-in
  2. 把 reactions 的类型从 List<Reaction> 改成 ImmutableList<Reaction>kotlinx-collections-immutable)——编译器不再需要你的承诺,直接认定 stable
  3. MessageList
     的 messages 参数同理,改成 ImmutableList<Message> 或者用 @Immutable data class 包一层

方案 1 的坑:@Immutable 是开发者对编译器的承诺,如果实际上被修改了,会导致 UI 不更新(stale state 但不重组)。只在确认不可变时用。

这种诊断不靠 skill 做不到——AI 的训练语料里几乎没人把 compiler reports 的解读流程写出来,它自己未必记得这个命令怎么开、输出怎么读、<runtime stability> 和参数级 stability 有什么区别。配上 skill 之后它会主动建议跑报告、知道每个字段是什么意思、能把报告里抽象的 “unstable” 翻译成”改哪一行代码就能解决”。

共同点

三个工作流里 AI 的能力没有变化——还是同一个模型,推理没升级。变化的是它能读到的参考资料(skill)和能调到的工具链(Android CLI)。真正的生产力来自两者的接合:skill 给它领域知识,CLI 给它现场数据,AI 负责把两边拼起来。

Skill 不是让 AI 变聪明,是给它配了一本手册 + 一套仪表盘。

是否推荐:适用 / 不适用 / 注意事项

不下死结论。按场景自己判断。

适用场景

  • 项目里 Compose 代码量大、AI 辅助写代码的比例高
    reference 覆盖面广这个优势能真正发挥出来。
  • 项目涉及 Multiplatform / TV / Material3 Motion / Styles API 这类细节多的分支
    这几块 AI 的训练语料本来就稀薄,skill 补得非常到位。
  • 团队对”AI 幻觉 API”敏感
    ——生产代码不容忍编译通过但运行时崩的写法。production-crash-playbook.md 能显著压低这类错误。
  • 换 AI 工具换得频繁
    同一份 skill 支持 8 个工具,从 Claude Code 换到 Cursor 不用重新配 project rules。
  • MIT 协议
    可以 fork 进内网、按团队需要裁剪、加自家的 playbook。

不那么适用的场景

  • 业务极简的应用
    只做列表和表单、几乎不触 performance / 动画 / 无障碍这些细节的项目,那 22 份 reference 里能用上的不多,边际收益低。但注意这和”纯 Android”没关系——只要项目里 Compose 的用法够深(复杂列表、自定义动画、自绘图形),哪怕完全不碰 CMP / TV,Review Mode 和 compiler reports 解读就值回装它的成本。
  • 团队已经积累了一套自己的 project rules
    不想再混一套外部 skill——两套风格可能打架。
  • context 预算紧张的场景
    SKILL.md 本体、触发到的 reference、偶尔下钻的源码摘录都要进 AI 上下文。大项目里如果你已经在用很多其他 skill 或 MCP 工具,要评估 context 够不够。

要注意的几点

  • 维护风险
    这是个人/小团队维护的开源项目,Compose 和 CMP 的版本升级跟进速度完全看维护者的活跃度。项目如果停更,reference 和 source code 都会落后于 androidx 主分支。
  • 手动更新
    Skill 装上不会自动升级,得手动 /plugin update(Claude Code)或 copilot plugin update(Copilot CLI)或者 git pull(手动集成)。建议每个 release 发布时过一眼 CHANGELOG。
  • 源码摘录是快照
    references/source-code/*.md 里的源码是从 androidx-main 和 jb-main 拉下来再提交到 skill 仓库的——不是实时同步。当前版本的快照时间线是维护者什么时候更新的,不是 androidx 主分支的最新状态。遇到非常新的 API 差异,还是得自己去 androidx/androidx 仓库核对。
  • 兼容性边界要自己留意
    Skill 声明的兼容版本是 Jetpack Compose 1.7+、Compose Multiplatform 1.8+、Kotlin 2.0+。比这旧的项目用上某些 reference 会出现 API 对不上的情况,得自己判断哪些章节适用。

我会装吗

如果你每天都在写 Compose、而且用 AI 写代码的比例超过 30%,装上试一两周看看是否顺手——迁移成本低(就是放一份 markdown),不合适随时删掉。

如果你的项目横跨 Android、Desktop、iOS、Web,CMP 那组 reference 一个人顶半个同事用。

如果你只偶尔写 Compose、写的也都是业务简单屏,那就算了——装了也体现不出价值。

收尾

Skill 这东西的本质,是给 AI 配一本你希望它读过的手册。aldefy/compose-skill 在做的事情很朴素:把 Compose 领域里散落在各种博客、官方文档、自己 App crashlog 里的知识,整理成一套分册的工具书,再加上 5.5 万行真实源码作证据,一起塞给 AI。

这不会让 AI 变聪明。但会让它在写 Compose 时少一点”凭印象回答”,多一点”查过资料再说”。

对一个日常写 Compose 的 Android 工程师来说,值不值得装,取决于你给 AI 打的那个下限——能接受”它有时候错、错了我能看出来”就够用;想让它尽量不错、错的时候有依据,那这类领域 skill 就是必要的基础设施。

感谢你看到这里,还请给我个 👍 / ♥️ / ↗️ 唷~ 🫶

❤️ 关注我 ❤️ 还有更多内容哦

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-05-10 21:37:06 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/602977.html
  2. 运行时间 : 0.159546s [ 吞吐率:6.27req/s ] 内存消耗:4,902.06kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=7724dd07cf45d8812783bc53cadb5776
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000837s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001358s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000461s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000488s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001048s ]
  6. SELECT * FROM `set` [ RunTime:0.007813s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001469s ]
  8. SELECT * FROM `article` WHERE `id` = 602977 LIMIT 1 [ RunTime:0.003962s ]
  9. UPDATE `article` SET `lasttime` = 1778420226 WHERE `id` = 602977 [ RunTime:0.000980s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000310s ]
  11. SELECT * FROM `article` WHERE `id` < 602977 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000615s ]
  12. SELECT * FROM `article` WHERE `id` > 602977 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001576s ]
  13. SELECT * FROM `article` WHERE `id` < 602977 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001950s ]
  14. SELECT * FROM `article` WHERE `id` < 602977 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.002145s ]
  15. SELECT * FROM `article` WHERE `id` < 602977 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.001096s ]
0.161322s