Android 基础入门教程:Adapter 基础讲解与 TaoToken 统一 Key 配置
1. 从 ListView 到 RecyclerViewAdapter 到底在做什么如果你刚开始学 Android第一次看到setAdapter这行代码时大概率会愣一下数据是我自己的布局也是我写的为什么中间还要塞一个 Adapter我当初也是这么想的直到自己动手写了第一个列表页才明白Adapter 就是数据和界面之间的翻译官。举个生活里的例子。你手里有一份 Excel 表格数据你想把它贴到墙上给全班看界面。你不能直接把 Excel 文件糊墙上得有人把每一行拆开、按格式抄到卡片上、再一张张贴上去。Adapter 干的就是这个活它知道你有多少条数据知道每条数据该塞进哪个控件的哪个位置然后一条一条地帮你把 View 造出来。在 Android 里跟 Adapter 打交道的控件主要有两个老一点的ListView和现在主流的RecyclerView。ListView 自己带滚动、自己回收 View你只要给它一个 Adapter 就行RecyclerView 把布局方式、动画、回收策略都拆成了独立的组件灵活但配置项更多。不管用哪个核心都是 Adapter。实际开发中你会遇到四种 AdapterArrayAdapter最简单只能显示一行文字适合做设置项、简单选项列表。SimpleAdapter稍微强一点可以把多个字段映射到多个控件上比如头像加昵称加签名。SimpleCursorAdapter专门对接数据库查询返回的 Cursor现在基本被 Room 加 RecyclerView 取代了。而BaseAdapter是抽象类前面三个本质上都是它的子类实际项目里用得最多的就是自己继承 BaseAdapter 重写方法。这篇文章我会带你把这几个 Adapter 都跑一遍每个都给完整可编译的代码。然后我们聊一个很多人忽略的问题写代码时如果本地 AI 辅助工具的 Key 散落在各个配置文件里换一个工具就要重新配一次非常烦。我会演示怎么把 endpoint 统一改到 TaoToken用一个 Key 管住所有工具。这部分跟 Adapter 本身没关系但对你日常写 Android 代码的效率影响很大。2. 环境准备与 TaoToken 统一 Key 配置在写代码之前先把两件事搞定Android 工程能跑起来以及你的 AI 辅助工具能正常调用模型。前者是本文示例的基础后者是让你后面写代码时少折腾。Android 这边你需要 Android Studio建议 Hedgehog 之后的版本新建一个 Empty Views Activity 项目语言选 Java最低 SDK 选 API 24 就行。本文所有示例都基于这个配置你可以直接复制粘贴运行。重点说第二件事。现在很多人写代码会同时用好几个 AI 工具IDE 里的补全插件、命令行的 coding agent、网页版的对话助手。每个工具都要填 API Key、Base URL、模型名换一个工具就重新配一遍Key 还容易泄露在配置文件里。TaoToken 的思路是把这些统一起来你只在 TaoToken 拿一个 Key然后把各个工具的 endpoint 都指向它模型切换、额度管理、调用记录都在一个地方看。具体怎么操作。先打开 https://taotoken.net/api-keys 创建一个 API Key复制下来存好。然后打开接入文档 https://taotoken.net/doc 对照你用的工具找配置方式。不同工具的配置位置不一样但核心就三样东西Base URL 填https://taotoken.net/apiAPI Key 填你刚创建的那串Model ID 填你要用的模型名比如claude-sonnet-4-5或gpt-4o以文档里的模型列表为准。如果你用的是 Claude Code 这类命令行工具配置通常写在~/.claude/settings.json或者项目根目录的配置文件里。如果是 Cline、Continue 这类 IDE 插件一般在插件的设置界面里填 Base URL 和 Key。Codex 的话看~/.codex/auth.json。不管哪个工具只要它支持自定义 OpenAI 兼容的 endpoint就能接进来。这里有个坑要提醒Base URL 末尾不要多加/v1或者斜杠不同工具对路径拼接的处理不一样多写了反而会 404。以文档里的写法为准。配好之后先别急着写业务代码用模型对话页面 https://taotoken.net/chat 发一条消息验证一下 Key 是通的省得后面调试时分不清是代码问题还是配置问题。3. 可复制配置三种 Adapter 的最小可运行示例这一节是全文的核心我会把 ArrayAdapter、SimpleAdapter、BaseAdapter 三个示例的完整代码都给你包括布局文件和 Activity。你新建一个项目按顺序把文件替换掉就能跑。3.1 ArrayAdapter一行文字的最简列表先看布局activity_main.xml就一个 ListView?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical ListView android:idid/list_test android:layout_widthmatch_parent android:layout_heightmatch_parent / /LinearLayout然后是MainActivity.javapackage com.example.adapterdemo; import android.os.Bundle; import android.widget.ArrayAdapter; import android.widget.ListView; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String[] strs {基神, B神, 翔神, 曹神, J神}; ArrayAdapterString adapter new ArrayAdapter( this, android.R.layout.simple_list_item_1, strs); ListView listTest findViewById(R.id.list_test); listTest.setAdapter(adapter); } }跑起来你会看到五行文字。android.R.layout.simple_list_item_1是系统自带的单行文本模板不用自己写布局。ArrayAdapter 的第二个参数就是 item 布局第三个参数是数据源可以是数组也可以是ListString。如果你想用资源文件里的数组在res/values/arrays.xml里写?xml version1.0 encodingutf-8? resources string-array namemyarray item语文/item item数学/item item英语/item /string-array /resources然后代码里改成ArrayAdapter.createFromResource(this, R.array.myarray, android.R.layout.simple_list_item_1)就行。系统还提供了simple_list_item_2两个文本框、simple_list_item_single_choice带单选钮、simple_list_item_multiple_choice带复选框等模板按需选用。3.2 SimpleAdapter头像加昵称加签名SimpleAdapter 适合 item 里有多个控件、每个控件对应数据里不同字段的场景。先写 item 布局list_item.xml?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightwrap_content android:orientationhorizontal android:padding8dp ImageView android:idid/imgtou android:layout_width64dp android:layout_height64dp / LinearLayout android:layout_widthmatch_parent android:layout_heightwrap_content android:orientationvertical android:paddingLeft8dp TextView android:idid/name android:layout_widthwrap_content android:layout_heightwrap_content android:textColor#1D1D1C android:textSize20sp / TextView android:idid/says android:layout_widthwrap_content android:layout_heightwrap_content android:textColor#B4B4B9 android:textSize14sp / /LinearLayout /LinearLayoutMainActivity.java里构造数据并绑定package com.example.adapterdemo; import android.os.Bundle; import android.widget.ListView; import android.widget.SimpleAdapter; import androidx.appcompat.app.AppCompatActivity; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class MainActivity extends AppCompatActivity { private final String[] names {B神, 基神, 曹神}; private final String[] says {无形被黑最为致命, 大神好厉害~, 我将带头冲锋~}; private final int[] imgIds {R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher}; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListMapString, Object listItem new ArrayList(); for (int i 0; i names.length; i) { MapString, Object item new HashMap(); item.put(touxiang, imgIds[i]); item.put(name, names[i]); item.put(says, says[i]); listItem.add(item); } SimpleAdapter adapter new SimpleAdapter( this, listItem, R.layout.list_item, new String[]{touxiang, name, says}, new int[]{R.id.imgtou, R.id.name, R.id.says}); ListView listView findViewById(R.id.list_test); listView.setAdapter(adapter); } }注意from数组里的 key 必须和 Map 里的 key 一一对应to数组里的控件 id 顺序也要跟 from 对齐。写反了不会报错但显示会错位这是新手最容易踩的坑。3.3 BaseAdapter实际项目里最常用的写法前面两个 Adapter 适合快速验证但真实项目里你几乎一定会自己继承 BaseAdapter。原因很简单你需要控制 View 的复用、需要处理点击事件、需要根据位置显示不同样式。下面是一个完整的 BaseAdapter 示例。item 布局list_item_base.xml?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightwrap_content android:orientationhorizontal android:padding12dp TextView android:idid/tv_index android:layout_width40dp android:layout_height40dp android:gravitycenter android:background#3F51B5 android:textColor#FFFFFF android:textSize16sp / TextView android:idid/tv_content android:layout_width0dp android:layout_height40dp android:layout_weight1 android:gravitycenter_vertical android:paddingLeft12dp android:textSize16sp / /LinearLayout自定义 Adapter 类package com.example.adapterdemo; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import java.util.List; public class MyBaseAdapter extends BaseAdapter { private final Context context; private final ListString data; public MyBaseAdapter(Context context, ListString data) { this.context context; this.data data; } Override public int getCount() { return data.size(); } Override public Object getItem(int position) { return data.get(position); } Override public long getItemId(int position) { return position; } Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView null) { convertView LayoutInflater.from(context) .inflate(R.layout.list_item_base, parent, false); holder new ViewHolder(); holder.tvIndex convertView.findViewById(R.id.tv_index); holder.tvContent convertView.findViewById(R.id.tv_content); convertView.setTag(holder); } else { holder (ViewHolder) convertView.getTag(); } holder.tvIndex.setText(String.valueOf(position 1)); holder.tvContent.setText(data.get(position)); return convertView; } static class ViewHolder { TextView tvIndex; TextView tvContent; } }Activity 里这样用package com.example.adapterdemo; import android.os.Bundle; import android.widget.ListView; import androidx.appcompat.app.AppCompatActivity; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListString data new ArrayList(); for (int i 1; i 20; i) { data.add(这是第 i 条数据); } ListView listView findViewById(R.id.list_test); listView.setAdapter(new MyBaseAdapter(this, data)); } }这里的关键是convertView复用和ViewHolder模式。ListView 滚动时会把划出屏幕的 View 回收getView的第二个参数就是被回收的 View。如果它不为 null你就不用重新 inflate 布局直接从 tag 里取出 ViewHolder 更新文字就行。少了这个判断列表一长就会卡这是性能优化的第一课。4. 验证请求与成功结果怎么确认真的跑通了代码写完了怎么确认它真的在工作分两步验证。第一步验证 Adapter 本身。把上面任意一个示例跑起来你应该看到列表正常显示数据滚动流畅没有卡顿。如果用的是 BaseAdapter 那个示例滚动到第 20 条再滚回来序号和内容应该完全对应不会出现文字错乱。这一步过了说明 Adapter 逻辑没问题。第二步验证 TaoToken 配置。打开你的 AI 辅助工具让它生成一段简单的 Android 代码比如「写一个把字符串数组转成 List 的 Java 方法」。如果工具能正常返回结果说明 Base URL、Key、Model ID 三样都配对了。如果返回 401说明 Key 不对或者没带上如果返回 404大概率是 Base URL 路径写错了如果提示 model not found就是 Model ID 填错了。你也可以直接用 curl 测一下接口通不通curl https://taotoken.net/api/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer 你的Key \ -d { model: claude-sonnet-4-5, messages: [{role: user, content: 用一句话解释什么是 Adapter}] }返回里有choices数组和内容就说明整条链路是通的。注意这里的路径是/api/v1/chat/completions跟你在工具里填的 Base URLhttps://taotoken.net/api拼起来正好。不同工具对路径的处理方式不同有的会自动补/v1有的不会以接入文档为准。验证通过之后你写 Android 代码时就可以让 AI 帮你生成 Adapter 模板、检查 ViewHolder 写法、解释报错信息不用再来回切换工具和重新配 Key。5. 本篇常见错排查401、local proxy failed 与 choices 为空这一节列几个你大概率会遇到的报错以及对应的排查思路。这些坑我自己都踩过写出来帮你省时间。401 Unauthorized。这个最直接Key 不对。检查三件事Key 有没有复制完整前后不要有空格、请求头里是不是Authorization: Bearer 你的Key这个格式、Key 有没有被禁用或过期。如果是在工具里配的确认你填的是 API Key 而不是别的什么 token。local proxy failed 或 connection refused。这个通常出现在你本地跑了代理工具、或者工具配置里填了localhost端口的场景。先确认 Base URL 填的是https://taotoken.net/api而不是本地地址。如果你之前配过别的 endpoint检查一下有没有残留的代理设置。这类报错跟 Adapter 代码无关纯粹是网络配置问题。返回结果里 reading choices 报错或 choices 为空。这种情况一般是请求体格式不对。检查messages是不是数组、model字段有没有拼错、JSON 有没有多逗号。有的工具会在你填的模型名前面自动加前缀导致实际请求的模型名不对这时候去工具的日志里看它真正发出去的请求体是什么。OAuth 相关报错。如果你用的是 Claude Code 这类带 OAuth 流程的工具有时候它会优先走账号登录而不是 API Key。检查配置文件里是不是同时存在两套认证信息把 OAuth 那部分清掉只留 API Key 配置。具体字段名参考接入文档里的示例。Adapter 相关的运行时错误。java.lang.IllegalArgumentException: column id does not exist这个报错出现在你用 SimpleCursorAdapter 但 Cursor 里没有_id字段的时候。解决办法是在查询时显式选出_id或者换用 BaseAdapter 自己绑定数据。另外NullPointerException在getView里很常见多半是findViewById返回了 null检查一下 item 布局里控件 id 有没有写错。列表显示空白。先确认setAdapter有没有调用、数据源是不是空的、getCount有没有返回正确数量。如果用的是自定义 Adapter在getCount里打个日志看看实际返回多少。还有一个隐蔽的坑如果你在getView里返回了 null列表也会空白但不报错。排查的顺序建议是先看 Logcat 的完整堆栈定位到具体行再确认是配置问题还是代码问题配置问题去看接入文档代码问题去看 Adapter 的四个方法有没有写全。大部分问题都能在这两步内解决。6. 把 Key 管起来把 Adapter 写熟Adapter 这部分我的建议是先把 BaseAdapter 的 ViewHolder 写法练到能默写。ArrayAdapter 和 SimpleAdapter 知道怎么用就行真实项目里遇到复杂列表你终究要自己继承 BaseAdapter 或者用 RecyclerView.Adapter。把getCount、getItem、getItemId、getView这四个方法的职责搞清楚把 convertView 复用和 ViewHolder 模式理解透后面学 RecyclerView 会轻松很多。至于 TaoToken 那部分核心价值就一句话一个 Key 管所有工具。你可以在 https://taotoken.net/api-keys 管理 Key在 https://taotoken.net/doc 查各个工具的接入方式。如果你长期写 Android 或者做 Agent 相关的开发可以看看 Coding Plan https://taotoken.net/coding-plan额度管理会更省心。写代码时想快速验证一个模型的能力直接开 https://taotoken.net/chat 就能对话不用装任何东西。最后留一个实用技巧把 Adapter 的 item 布局和 ViewHolder 字段命名保持一致比如布局里叫tv_nameViewHolder 里就叫tvName这样你写findViewById的时候不容易找错控件。这个习惯在 item 布局复杂的时候能帮你省很多调试时间。

相关新闻

小电机驱动方案解析:TLE995x搭配第7代MOSFET的可靠低成本设计

小电机驱动方案解析:TLE995x搭配第7代MOSFET的可靠低成本设计

做小电机控制这几年,我最大的感触是:真正的功夫不在算法,而在驱动电路怎么做得稳、做得省。车窗升降、座椅调节、电子水泵、散热风扇,甚至工业上的一些小型泵和阀门,本质都是几安培到几十安培的直流电机控制。电流看着…

2026/10/11 10:35:14 阅读更多 →
驱动开发从零到一:内核模块、设备树与调试实战指南

驱动开发从零到一:内核模块、设备树与调试实战指南

1. 为什么我要写《驱动之路》这个系列动笔写这个系列之前,我犹豫了挺长时间。市面上关于硬件驱动开发的中文资料不算少,但真正能让人从零开始、一步步跟着做下来的系统性内容,其实并不多。大部分要么是芯片原厂几百页的寄存器手册&#xff0c…

2026/10/11 10:34:14 阅读更多 →
芯片设计中的AI黑盒:风险识别与可控实践

芯片设计中的AI黑盒:风险识别与可控实践

1. 黑盒藏在设计链路的哪些环节,我该先盯住谁做芯片的人大概都经历过这种场面:后端工程师指着屏幕上一堆AI自动插入的缓冲器方案,说“这是工具优化出来的”。你问它为什么偏偏在这个位置插了两排buffer,回答往往是“模型认为这里时…

2026/10/11 10:34:14 阅读更多 →

最新新闻

桌面级Text2SQL工具:自然语言查数据库,离线、免GPU、零门槛

桌面级Text2SQL工具:自然语言查数据库,离线、免GPU、零门槛

1. 这不是又一个SQL生成器:为什么“自然语言驱动的桌面Text2SQL”值得单独开一篇最近在某高校实验室带一个模拟项目X,目标是让非技术背景的教研人员能直接用中文查教学评估数据——比如“上学期所有选修《教育心理学》且成绩低于75分的学生名单”。团队最…

2026/10/11 11:26:03 阅读更多 →
WinForm项目中Autofac生命周期管理:Scope边界与内存泄漏实战

WinForm项目中Autofac生命周期管理:Scope边界与内存泄漏实战

接手过几个WinForm项目,几乎每个都把Autofac当成"方便new对象"的工具:构造函数里写几个参数,容器一Resolve,齐活。直到内存曲线开始不对劲,或者某个窗体明明关了、后台却还在狂刷日志,才会有人想…

2026/10/11 11:26:03 阅读更多 →
集成验证与面试题精讲:构建可信微服务闭环

集成验证与面试题精讲:构建可信微服务闭环

1. 这不是一节普通的技术课:它解决的是“学了不会用、用了不敢讲”的真实断层“第07讲:集成、验证与面试题精讲”——光看标题,你可能以为这只是某套课程里的常规一讲。但在我带过二十多期不同背景学员的实际教学中,这一讲几乎总是…

2026/10/11 11:26:03 阅读更多 →
新一代电能数据采集终端:高稳定计量与边缘实时决策设计

新一代电能数据采集终端:高稳定计量与边缘实时决策设计

1. 项目概述:为什么“新一代电能数据采集终端”不是又一个概念包装?“新一代电能数据采集终端方案”——这八个字在电力自动化、智能配电、能源物联网领域,最近半年高频出现在招标文件、技术白皮书和某高校能源实验室的立项汇报里。但说实话&…

2026/10/11 11:26:03 阅读更多 →
深入解析 /proc/vmallocinfo:内核 vmalloc 内存泄漏排查实战

深入解析 /proc/vmallocinfo:内核 vmalloc 内存泄漏排查实战

1. 为什么内核开发者都绕不开 /proc/vmallocinfo第一次在生产环境里排查内存泄漏,是在一台跑了三天压力测试的服务器上。free -m显示可用内存还剩不少,但slabtop和meminfo里VmallocUsed那一栏的数字却一路往上爬,怎么都降不下来。当时翻遍了/…

2026/10/11 11:26:03 阅读更多 →
数仓DIM层六张维度表建模详解:从建表逻辑到ETL实践

数仓DIM层六张维度表建模详解:从建表逻辑到ETL实践

1. 建表前的整体思路:为什么DIM层剩下的维度都是“硬骨头” 数据仓库搭建到DIM层,很多人以为就是复制粘贴建表语句,实际上越往后越考验对业务的理解。前边的用户维度、商品维度、店铺维度,好歹还有现成的业务主键可以依赖&#xf…

2026/10/11 11:25:02 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →