AIDL多客户端回调管理:RemoteCallbackList实战与避坑
简介面向Android中高级开发者的AIDL跨进程通信IPC实战资源包完整演示如何通过AIDL实现多个客户端同时调用同一个服务端代码并兼顾多客户端并发访问时的线程安全与资源管理。资源共92个文件核心包含java源码、aidl接口定义、xml布局/配置、class编译产物及可直接安装的apk示例配套项目结构清晰适合初学者对照学习AIDL定义、Stub生成、Service绑定和RemoteException处理等关键环节。压缩包仅235KB轻量易用便于快速导入工程验证多进程通信逻辑。已有1049人学习下载可作为理解Android IPC机制、编写跨应用服务调用或优化Binder性能的参考样例。1. 多个客户端共用一个 AIDL 服务先搞清楚调用模型再动手做过跨进程通信的人都知道AIDL 刚上手时最容易写出「一个客户端对应一个服务」的 demoActivity 绑定 ServiceService 里 return 一个 Binder完事。但一旦你遇到「多个 App 进程同时连接同一个服务各自注册回调服务端还要把数据推给所有人」这种需求——比如一个后台下载服务同时被三个界面进程监听进度或者一个音乐播放服务要同时给通知栏、悬浮窗、手表端推当前曲目——同一个 Binder 实例能撑住吗并发调用会不会互相堵死回调会不会串线这些问题不解决联调时一定翻车。这篇我把完整的服务端、客户端代码和四个最容易踩的坑拆开讲照着复现一遍能省下你至少一个下午的排查时间。2. AIDL 多客户端服务的理论选型Binder 线程池与回调注册机制2.1 Binder 机制下多个客户端天然共享一个服务实例AIDL 的底层是 Binder。同一个 Service 组件不管有多少个客户端通过bindService()连上来系统只会创建一个服务实例onBind()也只会调用一次。所有客户端拿到的都是同一个 Binder 代理对象。所以「多个客户端调用一个服务器」这个需求本质上是多进程通过同一个 Binder 向同一个服务端对象发消息服务端需要有能力区分「消息来自谁」并且能主动向「注册过的客户端」推送。这个认知很重要。它决定了你的服务端代码必须是有状态的不能是onBind()里返回一个无脑处理请求的 Stub 就完事。State 要记录谁注册过、谁注销过、谁已经死了。我第一版做多客户端 AIDL 就栽在这以为 Binder 会自动维护客户端列表结果服务端想广播时压根不知道发给谁。2.2 为什么不能用 ArrayList 管理客户端新手最容易想到的方案服务端定义一个ArrayListICallback客户端 bind 成功后调registerCallback(ICallback cb)把回调塞进列表广播时 for 循环遍历。这个方案有两个致命问题。第一跨进程对象不能长期持有 native 引用。Binder 代理对象在不同进程里是降级为句柄的你直接存 Java 对象也没问题但客户端进程一死服务端持有的 Binder 代理会失效你无法感知遍历时就会抛出DeadObjectException。第二并发遍历与增删冲突。回调注册和消息广播很可能发生在不同 Binder 线程里ArrayList边遍历边删除会抛ConcurrentModificationException即使你加锁广播时频繁持锁也会拖慢所有客户端的跨进程调用。正确的做法是用RemoteCallbackListE。它是 Android 官方专门为跨进程回调注册设计的数据结构内部自己加锁线程安全并且它底层通过IBinder的linkToDeath自动感知客户端死亡死掉的回调会被自动移除不用你手动清。后面服务端代码全建立在它之上。2.3 服务端接口设计注册、注销、广播设计接口时要想清楚三个动作registerCallback(ICallback cb)客户端把自己暴露给服务端。unregisterCallback(ICallback cb)客户端主动下线避免服务端保留死回调。业务方法比如setMessage(String msg)服务端收到后向所有已注册回调广播。其中回调接口ICallback里放什么方法取决于你要推什么数据。推送普通字符串、int、Parcelable 对象都可以。如果推送的是 list 或 map注意只有 AIDL 支持的类型才能通过。下面给出接口文件。2.4 参数说明表AIDL 支持的数据类型与限制多客户端通信时回调里传的数据类型直接决定你能不能跨进程。这里列一张表避免写完 aidl 文件编译报错类型分类支持情况说明基本类型boolean/byte/char/short/int/long/float/double默认支持不需要 importString/CharSequence支持跨进程传的是副本不是引用List支持元素必须是 AIDL 支持类型服务端收到的是单向的 ArrayListMap支持同样要求 key/value 是支持类型Parcelable支持需要显式 import且要写in、out或inout方向AIDL 接口支持回调本身就是这样传入的注意AIDL 里传的 List/Map 类型是固定 ArrayList/HashMap你声明ListString收到的实现类就是ArrayList不要试图在接口里收自定义 List 实现。方向标记默认是in回调接口建议也用in客户端传 Binder 代理进来就够了不需要回传。3. 服务端完整实现RemoteCallbackList 管理多客户端连接3.1 aidl 接口文件定义先建两个 aidl 文件。一个是服务端的业务接口一个是客户端回调接口。回调接口放服务端进程用oneway关键字声明原因后面避坑章节再说。IMessageService.aidlpackage com.example.messaging; import com.example.messaging.IMessageCallback; interface IMessageService { void registerCallback(in IMessageCallback callback); void unregisterCallback(in IMessageCallback callback); void sendMessage(String msg); }IMessageCallback.aidlpackage com.example.messaging; oneway interface IMessageCallback { void onMessageReceived(String msg); }逻辑说明registerCallback和unregisterCallback是客户端生命周期管理sendMessage是业务入口。注释里已经写明in方向回调 Binder 代理只需要单向传入。oneway放在回调接口上表示客户端接收推送时不需要等待服务端返回避免阻塞服务端 Binder 线程。参数说明oneway只对声明它的接口里的所有方法生效。它改变的是调用方行为——调用onMessageReceived时客户端不会等服务端真正执行完而是立刻拿到void返回。这样即使客户端处理慢也不会占用服务端线程池的等待窗口。3.2 服务端 Stub 实现MessageService.java核心代码public class MessageService extends Service { private final RemoteCallbackListIMessageCallback callbackList new RemoteCallbackList(); private final IMessageService.Stub binder new IMessageService.Stub() { Override public void registerCallback(IMessageCallback callback) throws RemoteException { if (callback null) return; callbackList.register(callback); android.util.Log.d(MessageService, registered, size callbackList.getRegisteredCallbackCount()); } Override public void unregisterCallback(IMessageCallback callback) throws RemoteException { if (callback null) return; // unregister 返回 true 表示确实移除成功 boolean removed callbackList.unregister(callback); android.util.Log.d(MessageService, unregistered, removed removed , size callbackList.getRegisteredCallbackCount()); } Override public void sendMessage(String msg) throws RemoteException { sendToAllClients(msg); } }; private void sendToAllClients(String msg) { int count callbackList.beginBroadcast(); for (int i 0; i count; i) { IMessageCallback callback callbackList.getBroadcastItem(i); try { callback.onMessageReceived(msg); } catch (RemoteException e) { // 客户端进程已死或 binder 失效RemoteCallbackList 会稍后自动清理 android.util.Log.w(MessageService, callback failed: callback); } } callbackList.finishBroadcast(); } Override public IBinder onBind(Intent intent) { return binder; } Override public void onDestroy() { callbackList.kill(); super.onDestroy(); } }逻辑说明beginBroadcast()和finishBroadcast()必须配对调用。beginBroadcast内部会加锁并返回当前有效回调数量保证遍历期间不会有新注册或注销插入避免并发修改。getBroadcastItem(i)取出第 i 个回调。遍历中 catch 住RemoteException避免一个客户端崩溃拖垮整个广播流程。参数说明RemoteCallbackList的register()底层会对传入的callback调用linkToDeath客户端进程死亡时自动从列表移除所以你不需要在unregisterCallback里手动调用unlinkToDeath。getRegisteredCallbackCount()只用于日志观察生产环境频繁调用有额外开销建议只在注册/注销时打日志。3.3 注册与注销的并发处理RemoteCallbackList已经内部线程安全注册和注销不需要你额外加synchronized。但是sendToAllClients里如果除了回调还访问其他共享变量——比如最近一条消息的缓存、客户端身份标识 Map——那就必须自己处理同步。比如你要区分每个客户端的身份不能只靠回调对象因为RemoteCallbackList.getBroadcastItem(i)拿到的只是 Binder 代理没有办法直接反查客户端包名。常见做法是注册回调时由客户端额外传一个clientId字符串服务端维护MapString, IMessageCallback但这样又回到线程安全问题。我一般会避免自己维护映射。因为 Binder 代理对象本身可以调asBinder()拿到IBinder你可以用IBinder作为身份 key配一个ConcurrentHashMapIBinder, String存客户端标识配合linkToDeath在死亡回调里移除。这是后话如果需求只是广播RemoteCallbackList一个结构就够了别自己造并发列表。3.4 向所有客户端广播消息广播逻辑只有 beginBroadcast / finishBroadcast 中间那段需要拧紧。还有一个细节不要在广播循环里调用任何可能阻塞的同步方法尤其不要在这个循环里再调回IMessageService的业务方法。原因Binder 客户端调用服务端方法时服务端会从 Binder 线程池取一个线程执行如果你的广播回调是oneway客户端那边执行是异步的但服务端发起调用的这个线程会在每个callback.onMessageReceived(msg)上停留——如果客户端处理慢服务端线程池会被占满。所以广播推送建议先收集消息快照再统一推。比如sendMessage进来时先把msg存到volatile String lastMessage然后开一个新的普通线程去执行sendToAllClients让 Binder 线程尽快释放。具体代码可以这样Override public void sendMessage(String msg) throws RemoteException { lastMessage msg; // 从 Binder 线程中脱离避免广播阻塞调用方 new Thread(() - sendToAllClients(msg)).start(); }逻辑说明new Thread每次创建线程不优雅但比占用 Binder 线程池好。更严谨的做法是注入一个单线程ExecutorService广播任务串行排队避免多个客户端同时sendMessage导致广播乱序。参数说明executor 的核心线程数可以设为 1因为业务逻辑是「大家按顺序收到同一条消息」串行最合理。如果用多线程并发广播客户端接收顺序就没保证了。3.5 服务端如何感知客户端掉线RemoteCallbackList会在底层自动处理掉线但你要不要做「通知业务层」就看需求了。比如某个客户端掉线后需要更新数据库里的在线状态你需要知道「哪个客户端掉了」。实现方式register之前对callback.asBinder()主动调一次linkToDeath然后保存 binder 与客户端 id 的映射。其实RemoteCallbackList内部已经 link 过了你再 link 会重复你需要拿到死亡回调时自己判定。更省事的方案是放弃RemoteCallbackList直接用MapIBinder, IMessageCallback配合linkToDeath管理这样死亡回调里你能立刻知道IBinder是谁。代价是并发控制要自己写。一句话结论如果只是「死了就不给它推」用RemoteCallbackList自动清理足够如果还要「死后做业务收尾」自己维护MapIBinder, 客户端信息更直观。4. 多客户端调用的避坑排查绑定、死线程与回调泄漏4.1 新客户端绑定不上Service 未启动或 Intent 不匹配现象第二个客户端不同进程调用bindService()时onServiceConnected一直不回调Logcat 里也没有onBind被调用的迹象。第一个客户端却正常。原因两种情况最常见。第一Service 没有调用startService()拉起而bindService()在 5.0 之后要求 Service 必须处于启动状态否则第一次绑定后服务可能被系统回收绑定结果不稳定。第二客户端绑定时用的 Intent 里包含包名或action与 Service 在AndroidManifest.xml里声明的 intent-filter 不一致尤其第二个客户端是不同进程时隐式 intent 无法跨进程匹配必须显式指定package。解决在onCreate或 MainActivity 里先startService(intent)再bindService(intent, conn, BIND_AUTO_CREATE)。Intent 统一写成显式的代码里通过ComponentName或setClassName指定要么 service 位于同一 App 内要么客户端 App 能拿到服务端 App 的包名与类全路径。4.2 回调不触发Stub 没持有被 GC 回收现象客户端registerCallback返回成功后服务端广播了客户端回调却一次都没执行。Log 里也没异常。原因经典 GC 坑。客户端把回调对象注册给服务端后自己没保存这个回调对象的强引用。服务端持有的其实只是 Binder 代理客户端进程里执行回调的 Stub 对象如果没有强引用会被 GC 回收。Binder 代理活着但本地 Stub 已经没了消息自然丢失。我当初排查了这个坑两个小时最后发现回调对象是个局部变量方法退出后就被回收了。解决把回调对象赋值给 Activity 或 Application 的字段并保证unregisterCallback之前不置空。比如private IMessageCallback callback new IMessageCallback.Stub() { Override public void onMessageReceived(String msg) throws RemoteException { runOnUiThread(() - textView.setText(msg)); } };逻辑说明Stub对象必须长期存活。runOnUiThread是因为回调方法在 Binder 线程池中执行不能直接刷新 UI。如果回调需要修改 View一定要切主线程。参数说明如果回调里要弹通知、刷新列表建议回调只做数据接收然后通过回调所在进程的 Handler 或 LiveData 转主线程不要在 Binder 线程里做重操作。4.3 并发广播导致 Binder 死线程oneway 与同步调用的取舍现象客户端多了以后sendMessage响应越来越慢甚至整个应用卡死Logcat 里大量TransactionTooLargeException或DeadObjectException。服务端线程池被占满。原因回调方法没有声明oneway。默认 AIDL 是同步调用服务端调callback.onMessageReceived(msg)会阻塞等待客户端执行完。客户端几十个每个都慢 100ms服务端 Binder 线程池默认 16 个线程很快被打满后续所有调用排队。解决回调接口统一声明oneway。这样服务端调用回调后不等待执行结果线程立刻释放。注意oneway也有限制方法不能有返回值不能有 out/inout 参数。如果你确实需要客户端回报处理结果别用oneway改成客户端主动再调服务端方法传入结果异步闭环。4.4 客户端进程被杀死后服务端仍保留回调RemoteCallbackList 自动清理现象用ArrayList管理回调时客户端进程被用户划掉服务端还保留回调代理重复注册后列表越来越大广播也越来越慢。原因普通ArrayList无法感知 Binder 死亡通知服务端不知道客户端已经没了直到广播时抛出DeadObjectException才知道——但这时列表里的死对象已经积累了一堆。每轮广播都要多次踩中异常性能自然恶化。解决替换为RemoteCallbackList。自动移除的前提是客户端进程确实死亡Binder 驱动会发出死亡通知。如果是客户端进程还活着只是回调对象被 GC 了见 4.2RemoteCallbackList不会清理因为它看到的是 Binder 代理还活着。这个区别要记清楚死进程能自动清死对象不能。4.5 服务端 onDestroy 时忘记 kill 回调列表现象服务重启后客户端registerCallback没有报错但广播无法到达任何客户端新客户端注册后getRegisteredCallbackCount()返回 0。原因RemoteCallbackList是对外映射 Binder 代理的核心结构。ServiceonDestroy时如果不调用kill()内部注册的回调可能残留且kill()会统一unlinkToDeath释放底层引用。不调用的话部分系统版本下 Service 重建后这个列表状态异常导致注册不生效。解决onDestroy里务必调callbackList.kill()并且把单例 Service 里的静态列表引用置空。代码Override public void onDestroy() { callbackList.kill(); super.onDestroy(); }逻辑说明kill()之后这个RemoteCallbackList不能再用于注册服务一旦销毁重建就重新 new 一个列表。如果你的服务是单例模式服务端可能长期存活这个坑不明显一旦系统回收重建不 kill 就会出玄学问题。5. 多客户端场景的验证与效率技巧压测、日志与运行期调试代码写完怎么证明「多个客户端真的同时接上了同一个服务」我常用的验证方式是做一个小工具界面服务端进程开一个控制页实时显示注册回调数量每个客户端进程模拟成不同身份的注册者。用两个 AVD 或一台真机加一个模拟器分别启动两个客户端实例验证三件事。第一件事两个客户端都注册后服务端日志里的registered, size是否递增到 2。这个最简单但要注意同一个 App 的两个实例如果跑在同一进程里不算多进程要验证多客户端就要让两个 App 打包签名后分别安装或者同一个 App 用android:process:remote开两个进程。第二件事杀掉其中一个客户端进程服务端下次广播前先打一条getRegisteredCallbackCount()的日志确认数量自动减一。这里有个时间窗口Binder 死亡通知是异步的进程被杀后 12 秒内列表可能还显示旧数量别急着断言失效。第三件事连续向服务端发送 500 条消息观察客户端是否全部收到且接收顺序与发送顺序一致。广播是串行执行时顺序基本一致如果你用了多线程并发广播顺序可能乱需要客户端在回调里打印序号核对。压测代码放在客户端onMessageReceived里统计计数每收到一条打一个点最后对比服务端发送总数。压测脚本不必写完整核心就是服务端记录发送序号客户端记录收到序号比对差值。比如private void sendToAllClients(String msg, int seq) { int count callbackList.beginBroadcast(); for (int i 0; i count; i) { IMessageCallback cb callbackList.getBroadcastItem(i); try { cb.onMessageReceived(seq seq : msg); } catch (RemoteException e) { // 忽略死回调 } } callbackList.finishBroadcast(); }逻辑说明序号由服务端生成从 1 累加到 500。客户端收到后打印日志如果最后收到的最后序号 500且中间没有缺失说明广播链路是通的。这里的seq拼接在msg里是偷懒做法更规范的做法是定义一个MessageDataParcelable 类字段包含 seq、content、timestamp跨进程传对象比拼字符串健壮。最后一个技巧调试时把TransactionTooLargeException的阈值提前暴露出来。Binder 单次事务数据量限制在 1MB 左右但多个客户端同时传输时每个事务都应控制在 100KB 以下最稳。如果你的广播消息超过 100KB比如图片 base64 字符串回调到达率会明显下降。解决方法是把大数据拆成小块或者传到文件路径让客户端自己读不要在 AIDL 里直接传大 payload。从那以后我每次做多客户端 AIDL 服务都会强制把「注册数量日志、死亡回调验证、并发序号比对」这三个环节走一遍发现ArrayList管理回调就直接重写发现回调忘存引用就先补字段发现同步回调没有oneway就先改接口。这套流程帮我避开了大部分线上翻车点。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

量子计算编程:范式革命与开发者必备技能

量子计算编程:范式革命与开发者必备技能

1. 量子计算带来的编程范式革命传统计算机使用二进制比特(0或1)作为信息处理的基本单位,而量子计算机则利用量子比特(qubit)的叠加态和纠缠态实现并行计算。这种底层差异将彻底改变我们编写软件的方式。量子比特可以同…

2026/10/15 13:18:50 阅读更多 →
MCP 的那些“坑”!从工具调用到提示注入,一次讲透

MCP 的那些“坑”!从工具调用到提示注入,一次讲透

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

2026/10/15 13:18:50 阅读更多 →
哥德巴赫猜想升级版:三素数之和算法解析

哥德巴赫猜想升级版:三素数之和算法解析

1. 题目背景与问题解析哥德巴赫猜想是数学史上最著名的未解决问题之一,其基本表述为"任一大于2的偶数都可写成两个素数之和"。这道P1579题目作为其升级版,通常会给出更复杂的约束条件或求解要求。在实际编程解题中,我们需要先理解题…

2026/10/15 13:17:50 阅读更多 →

最新新闻

S变换在配电网混合线路故障选线中的应用

S变换在配电网混合线路故障选线中的应用

1. 项目背景与核心价值在配电网系统中,电缆-架空线混合线路的故障选线一直是困扰运维人员的难题。传统基于工频量的选线方法在面对高阻接地、间歇性电弧等复杂故障时,往往会出现误判。而S变换作为一种时频分析工具,能够同时保留信号的时间与频…

2026/10/15 13:58:46 阅读更多 →
基于S变换的配电网混合线路故障选线方法

基于S变换的配电网混合线路故障选线方法

1. 项目背景与核心价值在配电网系统中,电缆-架空线混合线路的故障选线一直是个棘手问题。传统基于工频量的选线方法在面对这类混合线路时,往往会因为线路参数差异大、故障特征复杂而失效。我在某地区电网的实际运维中就遇到过这样的案例:一条…

2026/10/15 13:58:46 阅读更多 →
1688图片搜索API技术内幕:从特征提取到向量匹配的工程实现

1688图片搜索API技术内幕:从特征提取到向量匹配的工程实现

图片搜索这件事,表面上看是"传一张图,返回一堆相似商品",但真正落到工程实现上,它是一条从像素到向量的完整流水线。1688的图片搜索API背后,核心要解决的是"如何让机器理解一张商品图里到底有什么&…

2026/10/15 13:58:46 阅读更多 →
乱抛垃圾行为识别监测系统

乱抛垃圾行为识别监测系统

城市公共街道、小区园区、公园广场、环卫责任片区、垃圾桶周边等公共区域,是市容环境治理与文明城市建设的核心场景。日常公共环境管理中,市民随手乱扔纸屑、果皮、包装袋、废弃杂物,垃圾桶旁乱堆乱放垃圾等不文明行为屡禁不止,不…

2026/10/15 13:58:46 阅读更多 →
AI辅助开发App全流程:从技术选型到上架发布的个人开发者实战指南

AI辅助开发App全流程:从技术选型到上架发布的个人开发者实战指南

1. 从零到一:AI辅助开发一款App的整体思路拆解1.1 为什么现在个人开发者也能独立完成App放在五年前,一个没有移动端经验的后端程序员想独立做出一款能上架的App,基本等于痴人说梦。UI设计、原生开发、后端接口、应用商店审核,每一…

2026/10/15 13:58:46 阅读更多 →
微信小程序预约挂号系统:号源并发扣减与排班逻辑实战

微信小程序预约挂号系统:号源并发扣减与排班逻辑实战

简介:这份资源是面向计算机专业毕业设计场景的微信小程序预约挂号系统完整论文资料,适合正在准备毕设选题、需要参考系统分析与设计写作范式的学生,以及希望了解SSM框架与微信小程序结合开发思路的开发者。压缩包共1个doc文件,约2…

2026/10/15 13:57:45 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/15 9:49:14 阅读更多 →