Android 进程与线程主线程阻塞问题、Handler、WorkThread、线程池工控实践工控设备卡成PPT大概率是你在主线程干了重活这篇把线程那点事儿掰碎了讲清楚。一、Android 进程与线程模型Android 应用启动时系统会为其创建一个进程并在该进程中启动一个主线程Main Thread。主线程也叫UI 线程负责处理界面绘制、用户事件分发、组件生命周期回调等。为什么不能在主线程做耗时操作核心原因一句话主线程承担着每 16ms 左右刷新一次屏幕60fps的重任。如果某个操作阻塞了主线程超过阈值系统就会弹出一个让所有开发者闻风丧胆的东西——ANRApplication Not Responding。常见的耗时操作包括网络请求HTTP / Socket 通信文件 I/O读写本地大文件数据库操作批量增删改查串口数据读取工控场景最常见的坑大量 CPU 计算图像处理、数据解析在工控板子上串口读取如果放在主线程数据量大的时候画面直接冻住按钮点不动这就是典型的主线程阻塞。二、ANR 机制详解ANR 不是随机触发的它有明确的超时阈值ANR 类型触发场景超时阈值Service TimeoutService 的 onCreate / onStartCommand 执行超时前台 20s / 后台 200sBroadcast TimeoutBroadcastReceiver.onReceive 执行超时前台 10s / 后台 60sInput Dispatch Timeout输入事件触摸/按键无响应5sContentProvider Timeout内容提供者发布超时10s注意一个常见误区很多人以为主线程耗时 5 秒就 ANR其实5 秒是输入事件派发超时。如果没有触摸事件进来主线程就算卡 10 秒也不一定弹 ANR——但界面肯定已经卡死了。真正让用户感知到的是输入无响应那条。工控设备往往是长时间无人触屏的所以 ANR 不一定弹出来但界面卡住一样致命——操作员按了停止按钮没反应设备还在跑。三、Handler 消息机制原理Handler 是 Android 线程间通信的核心机制涉及四个关键角色Message消息载体携带what标识、obj数据、arg1/arg2整型参数MessageQueue消息队列按时间排序的单链表结构Looper循环器不断从 MessageQueue 中取出 Message 分发给 HandlerHandler发送和处理消息的入口整个流程可以用一句话概括Handler 发送 Message → MessageQueue 入队 → Looper 循环取出 → Handler.handleMessage() 处理[子线程] Handler.sendMessage(msg) ↓ [MessageQueue] 按 when 排序入队 ↓ [Looper.loop()] 死循环轮询取出 ↓ [Handler.handleMessage()] 在 Handler 创建所在线程执行关键点Handler 的 handleMessage 在哪个线程执行取决于 Handler 在哪个线程创建。在主线程创建的 HandlerhandleMessage 就跑在主线程天然可以更新 UI。四、工作线程创建方式4.1 普通 Thread最原始的方式直接 new 一个线程newThread(()-{// 子线程执行耗时操作StringdatareadSerialPort();// 不能直接更新UI需要Handler切换}).start();缺点每次 new Thread 开销大无法管理线程数量容易造成 OOM。4.2 HandlerThread自带 Looper 的线程适合需要在该线程上创建 Handler 的场景HandlerThreadhandlerThreadnewHandlerThread(serial-worker);handlerThread.start();HandlerserialHandlernewHandler(handlerThread.getLooper()){OverridepublicvoidhandleMessage(NonNullMessagemsg){// 在HandlerThread线程中执行}};4.3 IntentService已废弃了解即可Android 8.0 后官方推荐用JobIntentService / WorkManager替代但在老项目里还能见到。它的特点是串行执行任务执行完自动停止。五、线程池使用线程池是工控开发中管理线程的最佳实践。核心类是ThreadPoolExecutor。5.1 参数详解ThreadPoolExecutorexecutornewThreadPoolExecutor(intcorePoolSize,// 核心线程数即使空闲也保留的线程数intmaximumPoolSize,// 最大线程数队列满后能扩展的最大线程数longkeepAliveTime,// 非核心线程空闲存活时间TimeUnitunit,// 时间单位BlockingQueueRunnableworkQueue,// 任务队列ThreadFactorythreadFactory,// 线程工厂可自定义线程名RejectedExecutionHandlerhandler// 拒绝策略);四种拒绝策略策略行为AbortPolicy默认抛出 RejectedExecutionExceptionCallerRunsPolicy由调用线程执行该任务DiscardPolicy直接丢弃DiscardOldestPolicy丢弃队列最老的任务再尝试提交5.2 工控场景线程池配置工控设备通常资源有限ARM Cortex-A 系列可能只有 1~4 核线程池不能无脑开大。推荐配置// 工控场景线程池核心2线程最大4线程队列128privatestaticfinalintCPU_COUNTRuntime.getRuntime().availableProcessors();privatestaticfinalintCORE_POOL_SIZEMath.max(2,Math.min(CPU_COUNT-1,4));privatestaticfinalintMAX_POOL_SIZECORE_POOL_SIZE*2;privatestaticfinalintQUEUE_CAPACITY128;publicstaticfinalThreadPoolExecutorWORK_EXECUTORnewThreadPoolExecutor(CORE_POOL_SIZE,MAX_POOL_SIZE,30L,TimeUnit.SECONDS,newLinkedBlockingQueue(QUEUE_CAPACITY),newThreadFactory(){privatefinalAtomicIntegermCountnewAtomicInteger(1);OverridepublicThreadnewThread(Runnabler){returnnewThread(r,control-worker-mCount.getAndIncrement());}},newThreadPoolExecutor.CallerRunsPolicy()// 队列满了让调用线程自己跑不丢任务);工控场景拒绝策略推荐CallerRunsPolicy——宁可让提交任务的线程自己执行也不能丢任务。丢一个继电器控制指令可能就是事故。六、工控实践串口数据读取用子线程 Handler 更新 UI下面是一个完整的串口通信线程 Handler 更新 UI 的实现publicclassSerialPortManager{privatestaticfinalintMSG_DATA_RECEIVED0x01;privatestaticfinalintMSG_ERROR0x02;// 主线程Handler用于更新UIprivatefinalHandlermUiHandler;// 串口工作线程privateHandlerThreadmSerialThread;privateHandlermSerialHandler;// 串口运行标志privatevolatilebooleanmRunningfalse;publicSerialPortManager(HandleruiHandler){this.mUiHandleruiHandler;}/** * 初始化串口读取线程 */publicvoidstart(){mSerialThreadnewHandlerThread(serial-read-thread);mSerialThread.start();mSerialHandlernewHandler(mSerialThread.getLooper()){OverridepublicvoidhandleMessage(NonNullMessagemsg){if(msg.whatMSG_DATA_RECEIVED){byte[]data(byte[])msg.obj;parseAndNotify(data);}}};mRunningtrue;// 启动读取循环mSerialHandler.post(this::readLoop);}/** * 串口读取循环在子线程执行 */privatevoidreadLoop(){while(mRunning){try{byte[]buffernewbyte[1024];intsizemInputStream.read(buffer);// 阻塞读取if(size0){byte[]datanewbyte[size];System.arraycopy(buffer,0,data,0,size);// 通过Handler切到主线程MessagemsgmUiHandler.obtainMessage(MSG_DATA_RECEIVED,data);mUiHandler.sendMessage(msg);}}catch(IOExceptione){mUiHandler.obtainMessage(MSG_ERROR,e.getMessage()).sendToTarget();break;}}}/** * 解析数据并通知UI */privatevoidparseAndNotify(byte[]data){// 协议帧解析帧头0xAA 长度 数据 校验if(data.length4)return;if(data[0]!(byte)0xAA)return;intlendata[1]0xFF;// ...解析逻辑}publicvoidstop(){mRunningfalse;if(mSerialThread!null){mSerialThread.quitSafely();}}}在 Activity 中使用publicclassMainActivityextendsAppCompatActivity{privateTextViewtvTempData;privateSerialPortManagermSerialManager;// UI Handler处理子线程发来的消息privatefinalHandlermUiHandlernewHandler(Looper.getMainLooper()){OverridepublicvoidhandleMessage(NonNullMessagemsg){switch(msg.what){caseSerialPortManager.MSG_DATA_RECEIVED:byte[]data(byte[])msg.obj;StringhexStrbytesToHex(data);tvTempData.setText(收到数据: hexStr);break;caseSerialPortManager.MSG_ERROR:Toast.makeText(MainActivity.this,串口错误: msg.obj,Toast.LENGTH_SHORT).show();break;}}};OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tvTempDatafindViewById(R.id.tv_temp_data);mSerialManagernewSerialPortManager(mUiHandler);mSerialManager.start();}OverrideprotectedvoidonDestroy(){super.onDestroy();mSerialManager.stop();}}6.1 核心要点总结要点说明串口读取必须在子线程InputStream.read()是阻塞调用放主线程必卡UI 更新必须切回主线程子线程直接操作 View 会抛异常Handler 是线程切换的标准方式轻量、可控、生命周期清晰HandlerThread 适合持续轮询场景自带 Looper省去手动 prepare/loopvolatile 控制线程退出保证可见性避免死循环工控开发中线程管理是基本功。串口、网络、定时采集每一路数据流都应该有独立的工作线程通过 Handler 或回调将结果送到主线程刷新界面。把线程用好设备才能跑得稳。
企业数字化 ERP 产品动态
相关推荐
Dify实战指南:2小时构建AI Agent与智能工作流 最近在尝试将大语言模型(LLM)能力集成到业务中时,你是否也遇到过这些困扰:想快速构建一个智能对话应用,却卡在复杂的模型API调用、上下文管理、工具集成和前端开发上?面对琳琅满目的Agent框架,感… · 2026/11/16 0:14:06
小红书无水印下载器XHS-Downloader:3分钟快速上手终极指南 小红书无水印下载器XHS-Downloader:3分钟快速上手终极指南 【免费下载链接】XHS-Downloader 小红书(XiaoHongShu、RedNote)链接提取/作品采集工具:提取账号发布、收藏、点赞、专辑作品链接;提取搜索结果作品、用户链接… · 2026/9/19 3:00:54
Reedline与Nushell集成深度解析:打造下一代Shell体验 Reedline与Nushell集成深度解析:打造下一代Shell体验 【免费下载链接】reedline A feature-rich line editor - powering Nushell 项目地址: https://gitcode.com/gh_mirrors/re/reedline
Reedline作为一款功能丰富的行编辑器,是Nushell的核心组件… · 2026/9/21 5:53:53
网上办电工证是骗局吗 含金量真的高吗 网上办电工证是骗局吗 含金量真的高吗 你是不是正为找工作发愁,急需特种作业证才能上岗?别急,先搞清楚网上办电工证是骗局吗,再看看这证到底有没有含金量,别一不小心花冤枉钱,耽误了机会。… · 2026/11/16 0:13:49
陕西建协电工证样板丢了怎么补办?网上查询流程全公开 陕西建协电工证样板丢了怎么补办?网上查询流程全公开 怕考不过白交培训费?你不是一个人。陕西建协电工证样板丢了,很多人第一时间想到的是补办流程复杂、耗时长,甚至不知道从哪开始。其实,只要掌握正确方法,补办并不难,关键是要 网上查询… · 2026/11/16 0:13:49
高压电工作业培训机构怎么选?上岗必备的证书你了解吗 高压电工作业培训机构怎么选?上岗必备的证书你了解吗 实操考试心里没底怕挂科,这是很多准备报考高压电工作业证书的朋友共同的困扰。特别是在平顶山这样的中小型施工企业,高压电工证是上岗必备的资质,没有它,很多岗位根本无法入职。高压电工作业培训机构… · 2026/11/16 0:13:49
麻城考电工证在哪值不值得考实操考试心里没底怕挂科 麻城考电工证在哪值不值得考实操考试心里没底怕挂科 实操考试心里没底怕挂科?麻城考电工证在哪?这可能是你最关心的问题。尤其是对于刚转岗的开封从业者来说,电工证不仅是上岗的“门槛”,更是职业发展的“跳板”。但很多人一听说要考试,心里就开始打鼓:… · 2026/11/16 0:13:49
工地太忙根本没时间复习考试?官方回应来了,哪里可以快速办电工证 工地太忙根本没时间复习考试?官方回应来了,哪里可以快速办电工证 工地太忙根本没时间复习考试,很多人一边赶工期一边想考电工证,结果一拖就错过了机会。最近不少朋友问“哪里可以快速办电工证”,我来给大家掰扯清楚,特别是对济源公路工程从业者来说,这… · 2026/11/16 0:13:48
工地太忙根本没时间复习考试?大沟电工作业怎么报名全攻略 工地太忙根本没时间复习考试?大沟电工作业怎么报名全攻略 工地太忙根本没时间复习考试?你不是一个人。现在越来越多一线电工朋友,特别是刚开始接触大沟电工作业的新手,最头疼的问题就是一边赶工期,一边还得抽空准备考试,时间紧任务重,复习都成了奢望。… · 2026/11/16 0:12:48
长春初级电工证怎么考?通过率揭秘全在这里 长春初级电工证怎么考?通过率揭秘全在这里 之前考的证在外省能不能转过来?这几乎是每个想从事电工工作的人都会问的问题。特别是那些在外地打拼多年、手里握着一张“外地电工证”的人,到了长春想继续干这一行,第一反应就是“我的证能用吗?”。今天我们就… · 2026/11/15 0:00:50
国内电工证报考条件与考试时间 低压电工证怎么考?学历不高也能报名,官方报名入口全在这 你是不是经常听说“电工证是入行门槛”,但又担心自己学历不够、经验不足,根本报不了名?别急,今天就带你从零了解【国内电工证】的报考流程、考试内容,还有怎么在 官方报名入口… · 2026/11/15 0:00:50
电工作业时如何断电?电子证书到底能不能全国通用? 电工作业时如何断电?电子证书到底能不能全国通用? 实操考试心里没底怕挂科,特别是电工作业时如何断电这一操作,不仅关系到你能不能拿到证书,更关系到以后能不能顺利上岗。很多人觉得这不过就是“断个电”,但其实这里面的门道可不少,稍有不慎就可能出错… · 2026/11/15 0:00:50
电工证培训的通知在哪考?别再被中介骗了 电工证培训的通知在哪考?别再被中介骗了 你是不是还在为 电工证培训的通知在哪考 发愁?网上搜了一堆信息,结果要么是挂羊头卖狗肉的培训机构,要么就是打着“包过”旗号的骗子?别急,今天我来给你讲讲, 电工证培训的通知… · 2026/11/16 0:00:34
电工证去哪个部门考核值不值得考 信阳转岗人真实经历分享 电工证去哪个部门考核值不值得考 信阳转岗人真实经历分享 怕考不过白交培训费?你不是一个人,信阳的李师傅去年刚转岗做电工,就因为没搞清楚电工证去哪个部门考核,差点交了8000块的培训费。别急,下面这份实操考试全攻略,告诉你电工证到底值不值得考… · 2026/11/16 0:00:34
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/15 1:51:20
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/15 4:02:19
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/15 3:02:05