尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
谷歌拨号器深入解析:T9搜索、通话记录与状态机实战
简介面向Android开发者与系统应用定制者提供基于Java实现的谷歌拨号器参考工程适用于Android N7.0系统同时兼容Android 5.0及以上设备可用于快速理解原生拨号器的界面组织与交互逻辑。压缩包大小约12.73MB已有1572人学习/下载。包内含APK构建产物及一组官方依赖库的配置声明包括appcompatActivity兼容与主题支持、recycleview联系人列表高效渲染、cardview卡片式容器、designMaterial Design控件与support-v13等便于对照学习Support Library在真实系统应用中的集成方式。借助项目代码可梳理拨号键盘、通话记录及联系人模块的实现脉络进而掌握从布局设计到事件处理的完整开发思路。资源附带开发者博客链接可追溯版本迭代与排错过程对研究AOSP风格应用或进行二次开发的工程师具有直接参考价值。1. 谷歌拨号器并不是你手机里那个拨号盘很多做系统定制或通讯录相关应用的开发者第一次拿到“谷歌拨号器”这个标题时以为要复刻的是手机桌面那个绿底白电话图标的简单拨号盘。实际打开 AOSP 里 Dialer 的源码你会发现它压根不是一个“盘”而是由拨号盘、通话记录、联系人联动、来电界面、通话状态管理五个大模块拼成的完整子系统。这也是我用它做二次开发时第一个被震到的地方一个拨号器在 AOSP 里能占到几千个文件调用链从 UI 一路埋到 Telephony 框架根本不是网上那些几百行的“简易拨号Demo”能比的。这篇文章想解决的是三类人的问题一是做 ROM 预置需要裁剪或定制拨号器的系统开发者二是想在自研应用里复刻 T9 搜索、通话记录这些体验的普通 App 开发者三是被“谷歌拨号器”这个名字误导、以为它有现成 APK 能直接抄的人。拨号器这类应用的特殊之处在于它同时踩了 UI 性能、数据库查询、系统权限、音频焦点四条线。任何一个环节处理不好用户感知的就是“卡一下、闪一下、没声音”。先说结论谷歌拨号器的核心价值不在界面而在“T9 拼音搜索 通话记录增量更新 通话界面状态机”这三块沉淀了多年的工程方案。下面按我踩过的路径把它的结构、关键代码和五六个大坑拆开讲。2. 拆开谷歌拨号器功能模块与源码骨架2.1 不是单个 App拨号器其实是四块独立代码拼起来的第一次用 Android Studio 打开 AOSP 的 Dialer 工程时我第一反应是“怎么有四个 application 入口”。谷歌拨号器在源码里的组织方式本质上是把不同功能拆成了独立的库和模块再通过同一个进程跑起来。这种拆分不是拍脑袋而是为了回答一个实际问题来电时系统可能不在拨号器界面电话怎么还能弹出来我一般会把 AOSP Dialer 按职责拆成四块理解。第一块是DialtactsActivity也就是用户看到的拨号盘和底部 Tab 容器它承载了拨号键盘、通话记录列表、联系人搜索三个页面的切换。第二块是CallLog通话记录模块它不直接读数据库而是通过CallLog.Calls这个系统 ContentProvider 拿数据。第三块是InCallUI也就是通话中那个显示头像、计时、挂断按钮的全屏界面它由InCallActivity承载。第四块是CallController负责把“用户按了拨号键”这个动作转换成“系统电话服务开始拨号”的指令。这个拆分直接影响到你改代码的方式。比如你要换掉拨号盘的按键音效只改 DialpadFragment 就行但你要改来电接听动画就得去 InCallUI 里找。模块之间通过 Intent 和 CallAudioMode 这类状态类通信而不是互相直接调方法。我见过有人为了省事让拨号盘直接 new 了一个通话记录页面出来结果返回键和动画全乱这就是没理解模块边界的代价。2.2 源码骨架从 DialtactsActivity 拉起整条调用链AOSP Dialer 的目录结构看起来吓人但入口是固定的。核心目录就这么几个packages/apps/Dialer/ ├── src/com/android/dialer/ │ ├── DialtactsActivity.java # 主入口拨号盘通话记录搜索的容器 │ ├── dialpad/ # 拨号盘 Fragment 与 T9 搜索逻辑 │ ├── calllog/ # 通话记录列表与增量加载 │ ├── incallui/ # 通话中的全屏界面InCallActivity │ ├── contact/ # 联系人联动、头像加载 │ └── util/ # 电话号码解析、格式化工具 ├── res/ └── AndroidManifest.xml这段目录树对应的是 AOSP 的标准工程结构。入口DialtactsActivity在 Manifest 里指定了launchModesingleTask和DEFAULT的 intent-filter这意味着系统拨号入口比如锁屏上的电话快捷图标、设置里的默认拨号应用都会把 Intent 投递到这个 Activity 上来。我自己的经验是拿到这个目录后先别急着看 UI先看 AndroidManifest.xml 里声明了哪些权限。拨号器需要的权限比普通应用多得多CALL_PHONE拨号、READ_CALL_LOG读通话记录、MODIFY_AUDIO_SETTINGS切换听筒/外放/蓝牙、FOREGROUND_SERVICE通话中保活。缺失任何一个都会出现“能打开但拨不了号”或“来电没声音”这种诡异问题。AOSP 默认在 priv-app 目录预置拨号器所以它还能拿到WRITE_CALL_LOG这种系统级权限普通应用别想这也解释了为什么第三方拨号器在 Android 10 之后越来越难做——权限收紧是系统层面的不是代码能绕过去的。3. 核心功能实现T9 搜索与通话记录的前世今生3.1 T9 搜索为什么难拼音映射只是第一步谷歌拨号器最让国产第三方拨号器头疼的功能就是 T9 搜索。所谓 T9就是数字键盘上每三个字母对应一个数字用户按“228”就能搜出“阿布”这种拼音首字母是 AB 的联系人。听起来很简单但真做起来要过三关数字到字母的映射、联系人姓名的拼音转写、以及“用户在键盘上输的到底是电话号码还是拼音首字母”的判定。先看数字到字母的映射表。这段代码是 T9 搜索的地基几乎所有拨号器实现都长这样// T9 按键到字母的映射索引对应键盘数字 0-9 private static final String[] T9_LETTERS new String[]{ , // 0不映射 , // 1不映射 abc, // 2 def, // 3 ghi, // 4 jkl, // 5 mno, // 6 pqrs, // 7 tuv, // 8 wxyz // 9 }; // 把一个字符转成对应的数字键 static int charToT9Key(char c) { char lower Character.toLowerCase(c); for (int i 2; i T9_LETTERS.length; i) { if (T9_LETTERS[i].indexOf(lower) 0) { return i; } } return -1; // 非字母字符比如空格、连字符 }这段代码看起来简单两个坑都藏在细节里。第一个坑是indexOf的查找效率如果联系人列表有几千人每个姓名都要遍历一遍 T9_LETTERS积少成多会造成拨号时卡顿。谷歌的做法是预先把联系人姓名转成 T9 数字串存进一个内存里的索引表而不是每次按键时现算。第二个坑是charToT9Key返回 -1 的情况姓名里的空格、分隔符如果直接丢弃搜索会错位。比如“张 三”转成 T9 是“94 7”如果按“947”搜空格在中间没匹配上就会漏结果。我自己的做法是保留非字母字符并跳过它们参与匹配而不是删除——这一点在联系人姓名带点号或短横线时特别重要。T9 搜索的查询本质是“用户输入的数字串是否是联系人 T9 串的前缀”不是完全相等。拿“张”来举例它的拼音是“zhang”T9 是“94264”用户输 942 就该命中输 9427 就不该命中。前缀匹配的判断逻辑要留好后续我做模糊搜索升级时直接复用了这套前缀判断。3.2 通话记录读取ContentResolver 不是随便查一下通话记录这块谷歌拨号器没有自己建表而是走系统提供的CallLog.CallsContentProvider。这个设计有好有坏好处是系统 Telephony 框架写入通话记录后拨号器不需要额外同步坏处是读取必须遵守系统的权限规则而且查询结果可能因为其他应用比如第三方拨号器写入脏数据而变得不可控。我见过很多人写通话记录查询时会犯一个经典错误在主线程直接执行 query导致列表滑动时卡顿。通话记录查询的标准做法是交给 Loader 或协程AOSP 里用的是 CursorLoader// 查询通话记录按时间倒序最多取最近 100 条用于列表展示 CursorLoader loader new CursorLoader( context, CallLog.Calls.CONTENT_URI, // 通话记录的内容 URI new String[]{ CallLog.Calls._ID, // 记录 ID CallLog.Calls.NUMBER, // 号码可能为空 CallLog.Calls.CACHED_NAME, // 缓存的联系人姓名 CallLog.Calls.DATE, // 时间戳 CallLog.Calls.DURATION, // 通话时长 CallLog.Calls.TYPE // 来电/去电/未接 }, null, null, CallLog.Calls.DEFAULT_SORT_ORDER LIMIT 100 // 按时间倒序分页 ); Cursor cursor loader.loadInBackground(); if (cursor ! null) { while (cursor.moveToNext()) { long date cursor.getLong(cursor.getColumnIndex(CallLog.Calls.DATE)); int type cursor.getInt(cursor.getColumnIndex(CallLog.Calls.TYPE)); String number cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER)); // 这里不要直接 new 对象塞进 List建议复用 ViewHolder 或直接用 RecyclerView 的 DiffUtil } cursor.close(); }这段代码有三个值得注意的细节。第一个是LIMIT 100直接拼在DEFAULT_SORT_ORDER后面这在 SQLite 里合法能有效避免一次查出几万条历史记录导致的内存暴涨。第二个是CACHED_NAME这个字段——如果联系人存在系统会先把名字缓存到通话记录里查询时不需要再去联系人表 JOIN省一次跨 Provider 查询。但要注意它可能为空显示时要做 fallback。第三个是cursor.close()不能省CursorLoader 虽然会管理但如果你在 Fragment 里手动持有 Cursor不关闭会让 ContentProvider 的连接池泄漏时间长了会出现“拨号器打开后其他应用读数据库变慢”的怪现象。通话记录要支持增量更新光靠查询不够。系统在每次电话挂断后都会向CallLog.Calls.CONTENT_URI发送通知拨号器要注册 ContentObserver 监听这个 URI 的变化收到通知后再重新查询。不然就会出现“电话刚挂断列表里没记录下拉刷新才出现”的体验问题。谷歌拨号器的做法是在CallLogFragment的onResume里注册 observeronPause里反注册避免后台时频繁回调。4. 通话界面的状态机来电、去电、挂断如何流转4.1 InCallActivity 的启动模式与来电弹出逻辑通话界面是所有拨号器里最容易翻车的地方。一个很常见的 bug 是用户正在刷微信突然来电通话界面没能弹出只在通知栏闪了一下。问题根源不在 Fragment而在 Activity 的启动模式没有配合来电场景。谷歌拨号器的 InCallActivity 在 Manifest 里声明了launchModesingleTask和excludeFromRecentstrue。前者保证无论来电时系统在哪个界面都只会复用同一个 InCallActivity 实例不会创建多个叠加后者保证用户按最近任务键时看不到通话界面——通话界面不是一个可以“回到”的页面挂了就应该消失。来电弹出还有一个更底层的要求锁屏状态下要能显示所以 InCallActivity 的 Window 需要设置FLAG_SHOW_WHEN_LOCKED和FLAG_TURN_SCREEN_ON。这两个 flag 在 Android 12 之后有变化不能直接在 window 上加得通过setShowWhenLocked(true)和setTurnScreenOn(true)这两个 Activity 方法来处理。我升级 targetSdk 到 31 的时候就因为还在用老的 Window flag 方式导致 Android 12 设备上来电只亮屏不显示界面。4.2 通话状态流转Idle、Incoming、Active、Disconnected通话界面的 UI 变化本质是状态驱动。Telephony 框架通过TelephonyManager.CallStateListener或 InCall UI 内部的CallList维护一个状态对象UI 根据状态去切换布局。状态机的四个核心状态需要明确。Idle是没有任何通话Incoming是来电响铃显示接听/挂断按钮Active是通话建立显示计时和挂断按钮Disconnected是通话结束界面开始播放挂断动画然后关闭。每个状态切换都伴随音频通道的变化这是拨号器最容易出问题的点。// 音频模式切换通话建立后切换到通信模式 AudioManager audioManager (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); switch (callState) { case TelephonyManager.CALL_STATE_IDLE: // 通话结束恢复普通模式释放音频焦点 audioManager.setMode(AudioManager.MODE_NORMAL); audioManager.abandonAudioFocus(null); break; case TelephonyManager.CALL_STATE_OFFHOOK: // 通话建立切到通信模式 audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); audioManager.requestAudioFocus(null, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN); break; }这段代码的关键在setMode的调用时机。必须在状态变成 OFFHOOK 之后再切不能在响铃阶段就切到MODE_IN_COMMUNICATION。否则会导致一个非常隐蔽的问题来电铃声会变小。原因是系统把音频模式切到通信模式后铃声通道被当成通话通道处理了。我在某款设备上排查这个问题花了整整一天最后发现是有人把这段代码放在了CALL_STATE_RINGING分支里。另一个注意点是abandonAudioFocus不能漏。通话结束后如果没释放音频焦点会导致后续通知音和媒体音量异常表现为“打完电话音乐没声了”。这个问题在国产 ROM 上尤其明显因为很多 ROM 会在通话结束后强制重置音频焦点但你的应用如果没释放会和系统互相拉扯。4.3 听筒、外放、蓝牙耳机切换的 AudioManager 参数通话中的音频切换是拨号器呼声最高的需求也是实现最容易踩坑的地方。常见的切换路径有三条听筒到外放、听筒到蓝牙耳机、外放到蓝牙耳机。以切到蓝牙耳机为例标准做法是// 切换到蓝牙耳机先设置音频路由再启动 SCO 连接 AudioManager audioManager (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); // 1. 启动蓝牙 SCO 连接需要 BLUETOOTH 权限 audioManager.startBluetoothSco(); // 2. 等 SCO 连接建立后再切换路由注意这里不能立即执行 audioManager.setBluetoothScoOn(true); // 3. 最后把音频模式保持为通信模式 audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);这段代码有三个讲究。第一startBluetoothSco()是异步的调完后不能马上setBluetoothScoOn(true)中间需要延迟 100ms 左右或者监听ACTION_SCO_AUDIO_STATE_UPDATED广播后再切换。第二setBluetoothScoOn(true)这个 API 在 Android 8 之后已经标记为 deprecated但实际在多数设备上仍然生效是兼容性最好的写法新代码建议直接用AudioDeviceInfo相关 API但要处理设备不支持的情况。第三蓝牙设备可能没有连接调用前要检查audioManager.isBluetoothScoAvailableOffCall()否则会抛IllegalStateException。这一块我总结的血泪经验是音频相关代码必须在真机上验证模拟器上所有音频路由都是一条虚拟通道你调十次都是“正常”的真机一跑就原形毕露。我做蓝牙切换时模拟器上稳如老狗上真机后出现“网约车接单后通话自己掉到听筒”的问题就是因为切到蓝牙后没监听断开广播蓝牙耳机一断系统自动把路由切回听筒但界面还显示蓝牙图标。5. 拨号器开发避坑指南5 个能让你加班到深夜的问题5.1 现象T9 搜索识别率低南方口音一搜一个空第一次做完 T9 搜索测试时我拿普通话标准的人名测全过。结果拿某开发者的花名一测直接搜索结果为 0。原因是他的名字里带“刘”拼音 liu但在很多方言区会读成“niu”转换成 T9 分别是 548 和 648不匹配。原因T9 搜索依赖姓名对应的拼音转写而拼音转写库用的是标准普通话声母韵母表不处理多音字和方言变体。这是字库层面的问题不是匹配算法能解决的。解决在拼音转写阶段做多音字补充表。比如“曾”要同时转成 ceng 和 zeng“单”要同时转成 dan 和 shan。转完主拼音后额外生成一组或多组候选 T9 串匹配时只要任意一组前缀命中就算命中。额外的好处是这种多候选策略顺便解决了部分前后鼻音不分的问题代价是索引表体积翻倍但一个联系人名字也就多占几十个字节可以接受。5.2 现象通话记录列表一直转圈Logcat 报 Permission Denial在 Android 10 之后读取通话记录需要READ_CALL_LOG权限而且这是一个运行时权限需要在界面里动态申请。但很多拨号器是预置于系统目录的 priv-app开发时直接在 Manifest 里声明了权限却忘了在代码里申请动态权限。真机上第一次运行没问题因为系统安装时已经授予了权限但如果你把代码打包成普通应用安装权限就是不弹窗、不授予查询直接抛SecurityException。原因priv-app 的权限授予机制和普通应用不同。预置应用可以在 Manifest 里声明android:permission直接被系统授予但普通应用必须在运行时通过requestPermissions请求。解决统一在onResume里检查权限没有就申请有才去 query。而且READ_CALL_LOG和READ_CONTACTS建议一起申请因为拨号器必然需要咖啡列表。如果用户拒绝界面要降级为“只显示号码、不显示姓名”而不是直接崩溃或白屏。5.3 现象挂断电话后拨号器界面黑色的返回桌面再进来还是黑的这个现象我在联系某设备厂商的定制 ROM 时遇到过。通话结束InCallActivity 应该 finish但实际整个进程像是被冻结了再打开桌面图标界面是一块黑屏。原因InCallActivity 的finish()被调用了但 Fragment 里的动画还在跑onDestroy里没有及时移除动画回调导致主线程消息队列被一个回调节目卡住。黑屏的本质是 window 已经销毁但 view 还持有已经失效的 surface绘制时拿不到缓冲只能吐黑色。解决在onStop里移除所有 view 动画onDestroy里清空 Fragment 的 childFragmentManager。更重要的是不要在动画回调里做状态保存。我的一般做法是挂断时立即设置一个isFinishing标志位所有动画回调收到这个标志后直接 return不执行任何 UI 操作。5.4 现象来电时接听按钮点了没反应再点一下才行接听按钮的点击事件做了防抖但防抖的阈值设得太长500ms导致用户连续快速点击时第一次点击被当作防抖忽略第二次点击才真正触发。用户感知就是“要按两下”。原因接听按钮绑定了双击/防抖逻辑目的是防止口袋误触但 Android 系统层面点击事件的判定在自定义 view 里重新实现了导致系统的手势识别和应用的防抖逻辑叠加阈值翻倍。解决口袋防抖不要放在点击事件里做而是用onInterceptTouchEvent拦截误触即可。具体做法是判断触摸区域是否超出按钮边界超出就拦截。点击事件本身只做isFinishing检查不做延时。5.5 现象蓝牙耳机通话时微信语音没声音通话中切到蓝牙挂断后微信语音播放没声音。这不是拨号器的问题是音频焦点没有释放干净。原因通话界面在Disconnected状态时offhook分支里abandonAudioFocus可能没有被调用因为状态机的回调顺序是先走onCallRemoved再走onStateChanged你写在onStateChanged里的释放代码没执行到。解决音频释放不要只写在单一分支里要在Disconnected和onDestroy都调用一次释放方法。释放方法本身要做幂等处理多次调用无副作用。这是我被坑得最疼的一次因为问题只在“挂着蓝牙耳机打完电话再切到微信”这个路径上出现普通测试完全复现不了。6. 进阶用法把拨号器从“能用”做成“好用”的四个细节前四章讲的都是把功能跑通这章聊点真正拉开差距的细节。第一是通话记录分页别学 AOSP 一次查 100 条真实设备上三年通话记录能有几万条RecyclerView 加载后滑动越来越卡。我验证过的最佳实践是用CursorLoader配合LIMIT 20 OFFSET 0做分页用户滑到底部自动加载下一页每页 20 条足够流畅。配合DiffUtil只更新变化的行性能能保持稳定。第二是号码格式化的时机。不要把电话号码格式化放在onBindViewHolder里做格式化是正则匹配加字符串拼接几千条记录瞬间就能卡掉十帧。我的一般做法是在查完数据库、还没进 RecyclerView 之前就把所有号码格式化成展示字符串列表里只做直接取值。查询阶段慢一点无所谓UI 线程必须零计算。第三是联系人头像加载要克制。联系人头像如果每次都去 ContentProvider 按 phone 查列表会卡成一帧帧的。正确做法是用联系人 ID 做 key内存缓存 磁盘缓存两级缓存不到才走 Provider 查询。而且头像和名字是两类数据建议分开加载名字走通话记录的CACHED_NAME头像单独查这样即使头像没加载出来名字已经显示了视觉上不会出现一通空白。第四是来电界面的接听延迟。有些设备上 InCallActivity 从广播到显示要 200ms 以上这个期间用户看到的是黑屏一闪。我验证过有效的做法是在监听到CALL_STATE_RINGING时就提前把 window 的setShowWhenLocked打开而不是等 Activity 创建完。来电场景下系统对 Activity 创建速度有严格超时超过阈值会直接抛弃界面所以能前置的初始化都不要拖到onCreate里。这几个细节做完后拨号器给人的感觉从“能用”变成了“顺手”。我自己的习惯是每改一次音频逻辑都会在真机上循环测三轮蓝牙连接与否、锁屏与否、接地气与否。拨号器这种应用用户每天至少碰一次而且必须在 100ms 内有反应任何一次卡顿都会被记住。谷歌拨号器的源码不是用来背的是用来当参照系的。对照它去审视自己的实现比从零发明要省力得多。希望这篇笔记能让你在这个方向上少走我走过的弯路。本文还有配套的精品资源点击获取
RELATED

相关推荐

KITTI数据集3D目标检测可视化:坐标系变换与点云投影全解析

KITTI数据集3D目标检测可视化:坐标系变换与点云投影全解析

KITTI数据集在3D目标检测里的地位,基本等同于视觉领域的"Hello World"。入门第一篇聊完怎么下载和解析数据格式之后,这次我打算把可视化这件事彻底讲透。不是教你怎么点一个"可视化按钮",而是把KITTI数据集每一帧背后的四…

📅 2026/10/15 14:27:08
从Sora到DiT:视频生成模型架构迁移与实战指南

从Sora到DiT:视频生成模型架构迁移与实战指南

1. 从Sora说起:为什么视频生成突然集体转向DiT如果你这两年一直在关注视频生成这个赛道,应该会有一种很强烈的感受:2024年之前,大家还在各玩各的,有基于U-Net的扩散模型,有自回归的Transformer方案&#xf…

📅 2026/10/15 14:27:08
C#直连西门子S7-1200/1500 PLC实战:S7NetPlus通信三道关与避坑指南

C#直连西门子S7-1200/1500 PLC实战:S7NetPlus通信三道关与避坑指南

简介:本资源是一套基于C#与S7.NET库实现西门子S7系列PLC通信的完整可运行工程,面向工业自动化领域初/中级开发者、工控软件工程师及高校自动化专业学习者,解决C#环境下PLC数据读写、连接管理与基础调试等核心实践问题。压缩包共41个文件&…

📅 2026/10/15 14:27:08
MORE NEWS

更多资讯

📰

批量Excel转CSV工具:pandas+glob+click实战指南

简介:这是一款面向Windows平台开发者的轻量级Excel批量转CSV工具,专为需高效处理大量xls/xlsx报表的办公自动化、数据清洗及ETL预处理场景设计。资源包含完整VS2005工程(含sln/dsw/vcproj等项目文件)、C源码(7个头文件…

📰

C++状态模式在工业控制系统中的应用与实践

1. 状态模式基础认知我第一次接触状态模式是在开发一个工业控制系统的报警模块时。系统需要根据设备的不同运行状态(待机、运行、故障、维护)触发差异化的报警策略,如果直接用if-else堆砌条件判断,代码很快就会变成难以维护的&quo…

📰

火星全球地形渲染实践:基于四叉树与LOD的精细调度

做火星全球地形渲染这件事,一开始我以为最麻烦的是“火星长什么样”,后来才发现真正的硬骨头在“怎么把几十亿个采样点塞进显卡里还能流畅转起来”。四叉树LOD这套组合,就是目前解决全球大尺度地形渲染最务实的一条路。这篇笔记我把整个实现过…

📰

新骆驼IPTV完美版后端源码部署与二次开发实战指南

简介:这份资源是新骆驼IPTV完美版的后端源码与安卓APP源码压缩包,面向具备一定安卓或服务端基础的开发者,用于研究电视直播系统的完整实现,并支持二次开发与功能自定义。包内以后端服务与前端应用代码为主,涵盖服务器管…

📰

Halcon相机标定全流程:标定板选型、内参优化与RMSE排查

简介:面向计算机视觉与机器视觉开发人员,这是Halcon官方参考手册第6章Calibration(标定)的中文直译版,内容无删减,可作为算法工程师与检测设备调试人员理解相机标定原理、参数含义与操作流程的案头资料。手…

📰

制造业桌面云怎么选?4 款主流方案横向对比

数字化转型持续推进,制造车间、研发工位的终端管理难题逐步凸显。传统本地PC硬件老化快,数据分散存储,图纸与生产资料安全管控难度高,运维人员需要往返车间处理各类电脑故障。制造业桌面云依托虚拟化技术,把桌面系统集…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬