<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>首页 — 笔记</title>
    <link>https://xiewr.pages.dev/</link>
    <description>Obsidian 仓库同步发布的静态博客</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <atom:link href="https://xiewr.pages.dev/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title></title>
      <link>https://xiewr.pages.dev/about/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://xiewr.pages.dev/about/</guid>
      <description>&lt;p&gt;客户端开发。技术栈：&lt;strong&gt;Android&lt;/strong&gt;、&lt;strong&gt;HarmonyOS（鸿蒙）&lt;/strong&gt;、&lt;strong&gt;React Native&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;有过 &lt;strong&gt;短视频 / 直播&lt;/strong&gt; 场景下的 &lt;strong&gt;直播间搭建与业务落地&lt;/strong&gt; 经历。目前主要工作方向在 &lt;strong&gt;跨端与动态化&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;联系&lt;/strong&gt;：&lt;a href=&#34;mailto:wwrong.xie@gmail.com&#34;&gt;wwrong.xie@gmail.com&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title></title>
      <link>https://xiewr.pages.dev/%E6%8A%80%E6%9C%AF%E7%AC%94%E8%AE%B0/android-%E5%BD%92%E7%BA%B3/android-anr-%E9%97%AE%E9%A2%98%E8%AF%A6%E8%A7%A3/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://xiewr.pages.dev/%E6%8A%80%E6%9C%AF%E7%AC%94%E8%AE%B0/android-%E5%BD%92%E7%BA%B3/android-anr-%E9%97%AE%E9%A2%98%E8%AF%A6%E8%A7%A3/</guid>
      <description>&lt;h1 id=&#34;android-anr-问题详解&#34;&gt;Android ANR 问题详解&lt;/h1&gt;
&lt;h2 id=&#34;1-核心结论什么是-anr&#34;&gt;1. 核心结论：什么是 ANR？&lt;/h2&gt;
&lt;p&gt;ANR（Application Not Responding）是 Android 系统保护用户体验的最后防线。
它的本质是&lt;strong&gt;系统跨进程的超时监控&lt;/strong&gt;：系统核心进程（SystemServer）发现应用主线程未能在规定时间内响应特定事件，从而强制弹窗让用户干预（等待或关闭应用）。&lt;/p&gt;
&lt;p&gt;核心解决思路：&lt;strong&gt;将耗时操作移出主线程，并优化主线程的锁与资源争用。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;2-为什么需要-anr-机制&#34;&gt;2. 为什么需要 ANR 机制？&lt;/h2&gt;
&lt;p&gt;如果应用在主线程卡死，用户将无法进行任何交互，手机看起来像“死机”了一样。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;目的&lt;/strong&gt;：把“关闭卡死应用”的选择权交还给用户，避免劣质应用霸占系统资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;设计权衡（上帝视角监控）&lt;/strong&gt;：系统并没有去监控应用主线程的每一个函数调用耗时（那会带来巨大的性能开销）。系统只对&lt;strong&gt;特定的核心组件&lt;/strong&gt;和&lt;strong&gt;输入事件&lt;/strong&gt;进行超时监控。如果应用在主线程执行了 4 秒的耗时操作，只要没碰到输入事件和组件生命周期，系统是不会管的。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;3-anr-的触发场景与阈值&#34;&gt;3. ANR 的触发场景与阈值&lt;/h2&gt;
&lt;p&gt;发生 ANR 的场景严格限定在以下四类（分别对应不同的系统服务监控）：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;场景&lt;/th&gt;
          &lt;th&gt;触发阈值&lt;/th&gt;
          &lt;th&gt;监控负责人&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Input 触摸/按键&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;5 秒&lt;/td&gt;
          &lt;td&gt;InputDispatcher (WMS 体系)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;BroadcastReceiver&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;前台 10 秒 / 后台 60 秒&lt;/td&gt;
          &lt;td&gt;ActivityManagerService (AMS)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Service&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;前台 20 秒 / 后台 200 秒&lt;/td&gt;
          &lt;td&gt;ActivityManagerService (AMS)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;ContentProvider&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;10 秒&lt;/td&gt;
          &lt;td&gt;ActivityManagerService (AMS)&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;4-核心原理anr-是如何监控并触发的&#34;&gt;4. 核心原理：ANR 是如何监控并触发的？&lt;/h2&gt;
&lt;p&gt;Android 实现 ANR 的核心思想是**“跨进程监控”**：监控方在系统进程，被监控方在应用进程。主要分为两套模型：&lt;/p&gt;</description>
    </item>
    <item>
      <title></title>
      <link>https://xiewr.pages.dev/%E6%8A%80%E6%9C%AF%E7%AC%94%E8%AE%B0/android-%E5%BD%92%E7%BA%B3/android-context-%E5%8E%9F%E7%90%86%E4%B8%8E%E9%80%89%E5%9E%8B%E8%AF%A6%E8%A7%A3/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://xiewr.pages.dev/%E6%8A%80%E6%9C%AF%E7%AC%94%E8%AE%B0/android-%E5%BD%92%E7%BA%B3/android-context-%E5%8E%9F%E7%90%86%E4%B8%8E%E9%80%89%E5%9E%8B%E8%AF%A6%E8%A7%A3/</guid>
      <description>&lt;h1 id=&#34;android-context-相关问题&#34;&gt;Android Context 相关问题&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;面试一句话&lt;/strong&gt;：Context 是“当前应用上下文”的抽象接口，真正干活的是 &lt;strong&gt;ContextImpl&lt;/strong&gt;，&lt;strong&gt;ContextWrapper&lt;/strong&gt; 代理一层给 Activity/Service/Application 用；Application 的 Context 进程单例、生命周期最长，Activity/Service 各有一个。Context 个数 = &lt;strong&gt;1 个 Application + N 个 Activity + M 个 Service&lt;/strong&gt;。详见笔记《Android 面试·分章系统复习》相关章节。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;阅读建议&lt;/strong&gt;：先看 &lt;strong&gt;面试两问&lt;/strong&gt; 和 &lt;strong&gt;选型&lt;/strong&gt;，再 &lt;strong&gt;是什么 / 整体结构 / 创建时机&lt;/strong&gt;，最后 &lt;strong&gt;注意点&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;面试两问结论前置&#34;&gt;面试两问（结论前置）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;1. Application、Activity、Service 的 Context 有什么区别？&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;类型&lt;/th&gt;
          &lt;th&gt;生命周期&lt;/th&gt;
          &lt;th&gt;典型用途&lt;/th&gt;
          &lt;th&gt;注意&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Application&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;进程级单例，与进程同生共死&lt;/td&gt;
          &lt;td&gt;全局配置、单例、getSharedPreferences、getSystemService&lt;/td&gt;
          &lt;td&gt;不要长期持 Activity 引用，易泄漏&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Activity&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;随 Activity 创建/销毁&lt;/td&gt;
          &lt;td&gt;启动 Activity、布局 inflate、主题、startActivityForResult&lt;/td&gt;
          &lt;td&gt;带主题，和界面绑定&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Service&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;随 Service 创建/销毁&lt;/td&gt;
          &lt;td&gt;后台逻辑、getSystemService、不带 UI 的能力&lt;/td&gt;
          &lt;td&gt;无主题、无 UI&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;2. App 里有几个 Context？&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1 个 Application + 所有 Activity 实例数 + 所有 Service 实例数&lt;/strong&gt;（每个 Activity/Service 对应一个 Context）。&lt;/p&gt;</description>
    </item>
    <item>
      <title></title>
      <link>https://xiewr.pages.dev/%E6%8A%80%E6%9C%AF%E7%AC%94%E8%AE%B0/android-%E5%BD%92%E7%BA%B3/android-handler-%E6%B6%88%E6%81%AF%E6%9C%BA%E5%88%B6%E8%AF%A6%E8%A7%A3/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://xiewr.pages.dev/%E6%8A%80%E6%9C%AF%E7%AC%94%E8%AE%B0/android-%E5%BD%92%E7%BA%B3/android-handler-%E6%B6%88%E6%81%AF%E6%9C%BA%E5%88%B6%E8%AF%A6%E8%A7%A3/</guid>
      <description>&lt;h1 id=&#34;android-handler&#34;&gt;Android Handler&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;面试可先答：四件套 Message、MessageQueue、Looper、Handler；线程切换本质是多线程共享同一 MessageQueue，通过 Handler 投递、Looper 分发；子线程需 Looper.prepare() + loop()；注意内存泄漏与 removeCallbacksAndMessages。详见笔记《Android 面试·分章系统复习》第七章 Handler 机制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;阅读建议&lt;/strong&gt;：先看 &lt;strong&gt;应用场景&lt;/strong&gt; 与 &lt;strong&gt;四件套&lt;/strong&gt;，再 &lt;strong&gt;线程切换本质&lt;/strong&gt;、&lt;strong&gt;ThreadLocal&lt;/strong&gt;、&lt;strong&gt;同步屏障&lt;/strong&gt;，最后 &lt;strong&gt;HandlerThread 案例&lt;/strong&gt; 与 &lt;strong&gt;常见问题&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;应用场景&#34;&gt;应用场景&lt;/h2&gt;
&lt;p&gt;Android 更新 UI 必须在主线程执行。Handler 用于在不同线程之间传递消息，把「更新 UI」等任务投递到主线程执行。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;核心模块与架构四件套&#34;&gt;核心模块与架构（四件套）&lt;/h2&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;组件&lt;/th&gt;
          &lt;th&gt;作用&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Message&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;消息载体，含 &lt;code&gt;what&lt;/code&gt;、&lt;code&gt;obj&lt;/code&gt;、&lt;code&gt;target&lt;/code&gt;（归属 Handler）、&lt;code&gt;when&lt;/code&gt;（执行时间）&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;MessageQueue&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;按&lt;strong&gt;时间顺序&lt;/strong&gt;排列的优先级单链表&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Looper&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;线程内的死循环，从 MessageQueue 取消息并分发&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Handler&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;发送消息入队，并接收 Looper 回传的消息在对应线程处理&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;架构示意：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://github.com/guoxiaoxing/android-open-source-project-analysis/raw/master/art/native/process/android_handler_structure.png&#34; alt=&#34;12&#34;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;线程切换的本质数据如何跨越线程&#34;&gt;线程切换的本质：数据如何跨越线程？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;结论&lt;/strong&gt;：多线程&lt;strong&gt;共享同一个 MessageQueue 对象&lt;/strong&gt;，通过 Handler 引用实现跨线程投递。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;绑定引用&lt;/strong&gt;：Handler 创建时绑定一个 Looper（及该 Looper 唯一的 MessageQueue）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨线程入队&lt;/strong&gt;：任意线程调用 &lt;code&gt;handler.sendMessage()&lt;/code&gt;，底层都是操作该 Handler 持有的 &lt;code&gt;mQueue&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;同步&lt;/strong&gt;：&lt;code&gt;MessageQueue.enqueueMessage&lt;/code&gt; 内用 &lt;strong&gt;synchronized(this)&lt;/strong&gt; 保证线程安全。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;唤醒执行&lt;/strong&gt;：消息入队后，通过 Linux &lt;strong&gt;epoll&lt;/strong&gt; 唤醒正在阻塞的线程，由该线程的 Looper 取消息并执行。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;线程隔离threadlocal&#34;&gt;线程隔离：ThreadLocal&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;问题&lt;/strong&gt;：Handler 如何保证绑定的 Looper 就是目标线程的？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原理&lt;/strong&gt;：Looper 用 &lt;strong&gt;ThreadLocal&lt;/strong&gt; 存储，每个线程一份独立副本，保证「一个线程只有一个 Looper」，实现线程间资源隔离。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;进阶同步屏障sync-barrier&#34;&gt;进阶：同步屏障（Sync Barrier）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：&lt;code&gt;target == null&lt;/code&gt; 的特殊消息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：屏障后的&lt;strong&gt;普通消息&lt;/strong&gt;被挂起，只允许&lt;strong&gt;异步消息&lt;/strong&gt;通过。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：Choreographer 收到 VSYNC 时插入同步屏障，让 UI 绘制（异步消息）优先执行，保证流畅。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注意&lt;/strong&gt;：屏障须用 token 手动移除，否则普通消息会一直被阻塞。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;实战handlerthread&#34;&gt;实战：HandlerThread&lt;/h2&gt;
&lt;p&gt;子线程使用 Handler 的标准写法：&lt;/p&gt;</description>
    </item>
    <item>
      <title></title>
      <link>https://xiewr.pages.dev/%E6%8A%80%E6%9C%AF%E7%AC%94%E8%AE%B0/android-%E5%BD%92%E7%BA%B3/android-view-%E7%BB%98%E5%88%B6%E4%B8%8E%E5%B8%83%E5%B1%80/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://xiewr.pages.dev/%E6%8A%80%E6%9C%AF%E7%AC%94%E8%AE%B0/android-%E5%BD%92%E7%BA%B3/android-view-%E7%BB%98%E5%88%B6%E4%B8%8E%E5%B8%83%E5%B1%80/</guid>
      <description>&lt;h1 id=&#34;android-view-绘制与布局从应用到屏幕的渲染管线&#34;&gt;Android View 绘制与布局：从应用到屏幕的渲染管线&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;本文目标&lt;/strong&gt;：打破“只背 View 三部曲”的局限，用一条完整的渲染管线把「应用层代码」到「屏幕显示」的整个链路串联起来。不仅知其然（流程是什么），更知其所以然（为什么要这么设计）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;阅读建议&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;想快速建立整体认知&lt;/strong&gt; 👉 读 &lt;a href=&#34;#%E4%B8%80%E6%A0%B8%E5%BF%83%E7%BB%93%E8%AE%BA&#34;&gt;一、核心结论&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;想了解一帧画面的诞生全貌&lt;/strong&gt; 👉 读 &lt;a href=&#34;#%E4%BA%8C%E6%B8%B2%E6%9F%93%E7%AE%A1%E7%BA%BF%E4%B8%8E-vsync-%E6%9C%BA%E5%88%B6&#34;&gt;二、渲染管线与 VSYNC 机制&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;想深入理解 View 三大核心步骤与底层数据结构&lt;/strong&gt; 👉 读 &lt;a href=&#34;#%E4%B8%89%E4%B8%BB%E7%BA%BF%E7%A8%8B%E9%81%8D%E5%8E%86%E8%AF%A6%E8%A7%A3measure--layout--draw&#34;&gt;三、主线程遍历详解（measure / layout / draw）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;遇到卡顿、拿不到宽高、自定义 View 等问题&lt;/strong&gt; 👉 读 &lt;a href=&#34;#%E5%9B%9B%E5%B8%B8%E8%A7%81%E5%9C%BA%E6%99%AF%E4%B8%8E%E6%8E%92%E9%9A%9C%E6%8C%87%E5%8D%97&#34;&gt;四、常见场景与排障指南&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一核心结论&#34;&gt;一、核心结论&lt;/h2&gt;
&lt;p&gt;不要把「只有 View 三步」当成渲染的全部；这三步仅仅是&lt;strong&gt;应用侧准备数据&lt;/strong&gt;的过程，真正的&lt;strong&gt;上屏&lt;/strong&gt;必须经过合成与显示链路。现代 Android 渲染的宏观分工如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;主线程（UI 线程）&lt;/strong&gt;：负责遍历视图树（measure / layout），并把绘制操作&lt;strong&gt;录制成图纸（draw 指令）&lt;/strong&gt;，不直接操作像素。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;渲染线程（RenderThread）与 GPU&lt;/strong&gt;：接手主线程录制好的图纸，利用 GPU 真正把指令变成像素（栅格化）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;系统合成守护进程（SurfaceFlinger）&lt;/strong&gt;：负责把各个 App 和系统 UI（状态栏、导航栏）的图层合成在一起，最终送到屏幕。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二渲染管线与-vsync-机制&#34;&gt;二、渲染管线与 VSYNC 机制&lt;/h2&gt;
&lt;p&gt;屏幕是一行行刷新的，如果代码随时随地去修改像素，极易出现画面撕裂。为此，Android 设计了基于 &lt;strong&gt;VSYNC（垂直同步信号）&lt;/strong&gt; 的节奏控制流水线。&lt;/p&gt;
&lt;h3 id=&#34;1-一帧画面的-5-个阶段全貌&#34;&gt;1. 一帧画面的 5 个阶段全貌&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant Disp as 物理屏幕 &amp;amp; VSYNC
    participant Choreo as 框架层 (Choreographer)
    participant Main as 应用主线程 (UI 线程)
    participant RT as 渲染线程 (RenderThread)
    participant SF as 系统合成进程 (SurfaceFlinger)

    Disp-&amp;gt;&amp;gt;Choreo: 1. 发出 VSYNC 节拍 (如每 16.6ms)
    Choreo-&amp;gt;&amp;gt;Main: 2. 触发回调，唤醒主线程
    Note over Main: 3. 遍历视图树&amp;lt;br/&amp;gt;(measure -&amp;gt; layout -&amp;gt; draw)
    Main-&amp;gt;&amp;gt;RT: 4. 同步绘制指令 (DisplayList)
    Note over RT: 5. GPU 栅格化，生成像素缓冲
    RT-&amp;gt;&amp;gt;SF: 6. 跨进程提交缓冲
    Note over SF: 7. 多窗口/图层合成
    SF-&amp;gt;&amp;gt;Disp: 8. 送显上屏 (等待下一次 VSYNC)
&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;节拍器（VSYNC）&lt;/strong&gt;：屏幕按固定频率发出的“滴答”声，统一渲染节奏。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;传达室与发令枪（Choreographer）&lt;/strong&gt;：应用调用 &lt;code&gt;invalidate()&lt;/code&gt; 时，是向它“注册”一个任务，等待下一个 VSYNC 发令枪响，才唤醒主线程干活。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;主线程遍历（View 三部曲）&lt;/strong&gt;：主线程确认视图大小（measure）、位置（layout），并&lt;strong&gt;录制&lt;/strong&gt;绘制指令（draw）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;独立包工头（RenderThread + GPU）&lt;/strong&gt;：主线程录制完图纸后立刻交接给它。它负责真正的“上色”（栅格化），让主线程能解放出来去响应触摸事件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;幕后大 Boss（SurfaceFlinger）&lt;/strong&gt;：Android 专属的独立系统守护进程。负责把手机所有图层跨进程汇总上屏。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;2-底层设计的演进与解惑&#34;&gt;2. 底层设计的演进与解惑&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;疑问一：为什么不在 VSYNC 到来“之前”一有空就提前画好？&lt;/strong&gt;
为了&lt;strong&gt;保证画面“绝对新鲜”&lt;strong&gt;并&lt;/strong&gt;将零散的更新“打包”&lt;/strong&gt;。等到 VSYNC 到来的一瞬间才去采集触摸位置和动画时间，画出来的才最贴合用户的当下操作，极大降低了输入延迟。同时避免 16.6ms 内多次无用的重复重绘。&lt;/p&gt;</description>
    </item>
    <item>
      <title></title>
      <link>https://xiewr.pages.dev/%E6%8A%80%E6%9C%AF%E7%AC%94%E8%AE%B0/android-%E5%BD%92%E7%BA%B3/android-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E7%9B%91%E5%90%AC%E6%BC%94%E8%BF%9B%E4%B8%8E%E4%BB%A3%E7%A0%81%E5%AF%B9%E7%85%A7/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://xiewr.pages.dev/%E6%8A%80%E6%9C%AF%E7%AC%94%E8%AE%B0/android-%E5%BD%92%E7%BA%B3/android-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E7%9B%91%E5%90%AC%E6%BC%94%E8%BF%9B%E4%B8%8E%E4%BB%A3%E7%A0%81%E5%AF%B9%E7%85%A7/</guid>
      <description>&lt;h1 id=&#34;android-生命周期监听演进史与对应实现&#34;&gt;Android 生命周期监听：演进史与对应实现&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;用途&lt;/strong&gt;：梳理 Android 生命周期监听机制的&lt;strong&gt;发展脉络&lt;/strong&gt;、&lt;strong&gt;对应时代的实现方式&lt;/strong&gt;，以及&lt;strong&gt;为什么&lt;/strong&gt;会发生这些演进。理解了「痛点与解法」，写代码时自然就能选对 API。&lt;br&gt;
&lt;strong&gt;建议阅读顺序&lt;/strong&gt;：先看 &lt;strong&gt;一、当前最佳实践速查&lt;/strong&gt;（结论），再按时间线阅读「为什么这么发展」。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一当前最佳实践速查结论&#34;&gt;一、当前最佳实践速查（结论）&lt;/h2&gt;
&lt;p&gt;不管历史怎么变，现在写代码请认准以下规范：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;场景&lt;/th&gt;
          &lt;th&gt;当前推荐做法&lt;/th&gt;
          &lt;th&gt;淘汰/避坑的做法&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;写生命周期感知的组件&lt;/strong&gt;（如相机、传感器）&lt;/td&gt;
          &lt;td&gt;实现 &lt;code&gt;DefaultLifecycleObserver&lt;/code&gt;，用 &lt;code&gt;lifecycle.addObserver()&lt;/code&gt; 注册&lt;/td&gt;
          &lt;td&gt;❌ 不再使用 &lt;code&gt;@OnLifecycleEvent&lt;/code&gt; 注解&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;在 Fragment 中操作 UI&lt;/strong&gt;（如更新 TextView）&lt;/td&gt;
          &lt;td&gt;必须绑定 &lt;strong&gt;&lt;code&gt;viewLifecycleOwner.lifecycle&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;❌ 不要绑定 Fragment 自身的 &lt;code&gt;lifecycle&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Kotlin 中收集 Flow / StateFlow&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;viewLifecycleOwner.lifecycleScope&lt;/code&gt; + &lt;code&gt;repeatOnLifecycle(STARTED)&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;❌ 不要直接在协程里裸 &lt;code&gt;collect&lt;/code&gt;（后台耗电）&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;进程级前后台判断&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;ProcessLifecycleOwner.get().lifecycle&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;❌ 不要在 BaseActivity 里自己计数&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二第一阶段手写回调的刀耕火种时代&#34;&gt;二、第一阶段：手写回调的「刀耕火种」时代&lt;/h2&gt;
&lt;h3 id=&#34;1-对应实现&#34;&gt;1. 对应实现&lt;/h3&gt;
&lt;p&gt;在 Activity / Fragment 的生命周期方法中，手动调用业务组件的注册与注销。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-kotlin&#34; data-lang=&#34;kotlin&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;MyActivity&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; AppCompatActivity&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; locationListener &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; MyLocationListener&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;onStart&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#cf222e&#34;&gt;super&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;.&lt;/span&gt;onStart&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        locationListener&lt;span style=&#34;color:#1f2328&#34;&gt;.&lt;/span&gt;start&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#57606a&#34;&gt;// 手动开始
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;onStop&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        locationListener&lt;span style=&#34;color:#1f2328&#34;&gt;.&lt;/span&gt;stop&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;  &lt;span style=&#34;color:#57606a&#34;&gt;// 手动停止
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#cf222e&#34;&gt;super&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;.&lt;/span&gt;onStop&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;2-为什么会演进痛点&#34;&gt;2. 为什么会演进？（痛点）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;God Activity（上帝类）&lt;/strong&gt;：UI 控制器里塞满了各种无关业务（定位、网络、视频播放）的启停逻辑，代码极度臃肿。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;极易出错&lt;/strong&gt;：&lt;code&gt;onStart&lt;/code&gt; 和 &lt;code&gt;onStop&lt;/code&gt; 必须对称。一旦开发者忘记写注销代码，就会导致&lt;strong&gt;内存泄漏&lt;/strong&gt;或后台崩溃。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组件无法独立&lt;/strong&gt;：业务组件无法做到「自给自足」，必须依赖外部 UI 控制器主动通知它。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三第二阶段aac-lifecycle-诞生与注解时代2017&#34;&gt;三、第二阶段：AAC Lifecycle 诞生与注解时代（2017）&lt;/h2&gt;
&lt;p&gt;为了解决上述痛点，Google 推出了 Android Architecture Components (AAC)，引入了 &lt;code&gt;Lifecycle&lt;/code&gt; 和 &lt;code&gt;LifecycleOwner&lt;/code&gt;。组件终于可以「自己监听」生命周期了。&lt;/p&gt;</description>
    </item>
    <item>
      <title></title>
      <link>https://xiewr.pages.dev/%E6%8A%80%E6%9C%AF%E7%AC%94%E8%AE%B0/%E6%8A%80%E6%9C%AF%E4%B8%93%E9%A2%98/%E9%94%81%E4%B8%8E%E5%B9%B6%E5%8F%91%E6%8E%A7%E5%88%B6---%E9%80%89%E5%9E%8B%E6%A6%82%E5%BF%B5%E4%B8%8E-java-%E5%AE%9E%E7%8E%B0/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://xiewr.pages.dev/%E6%8A%80%E6%9C%AF%E7%AC%94%E8%AE%B0/%E6%8A%80%E6%9C%AF%E4%B8%93%E9%A2%98/%E9%94%81%E4%B8%8E%E5%B9%B6%E5%8F%91%E6%8E%A7%E5%88%B6---%E9%80%89%E5%9E%8B%E6%A6%82%E5%BF%B5%E4%B8%8E-java-%E5%AE%9E%E7%8E%B0/</guid>
      <description>&lt;h1 id=&#34;锁的应用场景&#34;&gt;锁的应用场景&lt;/h1&gt;
&lt;p&gt;多线程访问共享资源时需要加锁，避免数据错乱。不同锁的代价和适用场景不同，选对了才能既有正确性又有性能。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;选型速查结论在前&#34;&gt;选型速查（结论在前）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;先看场景，再选手段：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;临界区较长&lt;/strong&gt;（如一段业务逻辑）→ &lt;strong&gt;互斥锁&lt;/strong&gt;（synchronized、ReentrantLock）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;临界区很短&lt;/strong&gt;（如改一个计数）→ &lt;strong&gt;自旋锁 / 原子变量&lt;/strong&gt;（AtomicInteger、LongAdder）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;读多写少&lt;/strong&gt;（如配置、缓存）→ &lt;strong&gt;读写锁&lt;/strong&gt; 或 CopyOnWrite、ConcurrentHashMap&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;冲突概率高&lt;/strong&gt; → &lt;strong&gt;悲观锁&lt;/strong&gt;（先加锁再操作）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;冲突概率低&lt;/strong&gt; → &lt;strong&gt;乐观锁&lt;/strong&gt;（先改再校验，版本号或 CAS）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;只关心「一个变量写了别人立刻看到」、且无复合操作&lt;/strong&gt; → &lt;strong&gt;volatile&lt;/strong&gt;（标志位、DCL 单例）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;需要超时、可中断、公平锁或多条件队列&lt;/strong&gt; → 用 &lt;strong&gt;ReentrantLock&lt;/strong&gt; 而不是 synchronized。&lt;/p&gt;
&lt;p&gt;加锁粒度尽量小，锁住的代码越少越好。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一核心概念&#34;&gt;一、核心概念&lt;/h2&gt;
&lt;h3 id=&#34;临界区&#34;&gt;临界区&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;临界区（Critical Section）&lt;/strong&gt;：访问共享资源、且在同一时刻只应被一个线程执行的那段代码。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;加锁就是为了保护临界区，保证不会有两个线程同时进入同一临界区。&lt;/li&gt;
&lt;li&gt;直观理解：&lt;strong&gt;被锁包住的那段代码&lt;/strong&gt;、&lt;strong&gt;需要互斥执行的那一段&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;锁类型总览&#34;&gt;锁类型总览&lt;/h3&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;锁&lt;/th&gt;
          &lt;th&gt;拿不到锁时&lt;/th&gt;
          &lt;th&gt;适用场景&lt;/th&gt;
          &lt;th&gt;典型例子&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;互斥锁&lt;/td&gt;
          &lt;td&gt;阻塞，让出 CPU&lt;/td&gt;
          &lt;td&gt;临界区较长&lt;/td&gt;
          &lt;td&gt;扣款、写日志&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;自旋锁&lt;/td&gt;
          &lt;td&gt;忙等&lt;/td&gt;
          &lt;td&gt;临界区很短&lt;/td&gt;
          &lt;td&gt;引用计数、原子变量&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;读写锁&lt;/td&gt;
          &lt;td&gt;读可并发，写独占&lt;/td&gt;
          &lt;td&gt;读多写少&lt;/td&gt;
          &lt;td&gt;配置表、缓存&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;悲观锁&lt;/td&gt;
          &lt;td&gt;先加锁再操作&lt;/td&gt;
          &lt;td&gt;冲突概率高&lt;/td&gt;
          &lt;td&gt;FOR UPDATE、synchronized&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;乐观锁&lt;/td&gt;
          &lt;td&gt;先改再校验&lt;/td&gt;
          &lt;td&gt;冲突概率低&lt;/td&gt;
          &lt;td&gt;版本号、CAS、Git&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;互斥锁&lt;/strong&gt;：阻塞、让出 CPU（有上下文切换）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自旋锁&lt;/strong&gt;：忙等、不释放 CPU，一般用 CAS；适合极短临界区。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;读写锁&lt;/strong&gt;：读共享、写独占；互斥锁、自旋锁、读写锁都是&lt;strong&gt;悲观锁&lt;/strong&gt;的实现。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;乐观锁&lt;/strong&gt;：先改再验证，失败则重试。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二可重入与不可重入&#34;&gt;二、可重入与不可重入&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题&lt;/strong&gt;：同一线程能否对&lt;strong&gt;同一把锁&lt;/strong&gt;连续加锁两次（或多次）而不死锁？&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
