浏览器渲染机制
关于浏览器渲染机制的整体介绍 一、从 URL 到页面渲染的完整流程URL 输入 ↓1. DNS 解析 → IP 地址 ↓2. TCP 三次握手 → 建立连接 ↓3. TLS 握手(HTTPS)→ 安全连接 ↓4. 发送 HTTP 请求 → 服务器返回 HTML ↓5. 浏览器解析 HTML → 构建 DOM 树 ↓6. 解析 CSS → 构建 CSSOM 树 ↓7. DOM + CSSOM → Render Tree(合成渲染树) ↓8. Layout(布局/回流)→ 计算每个节点位置 ↓9. Paint(绘制)→ 像素绘制 ↓10. Composite(合成)→ GPU 合成最终页面 二、解析 HTML 构建 DOM 树2.1 解析过程HTML 字节流 ↓ 字节 → 字符(解码) ↓ 字符 → Token(分词) ↓ Token → Node(构建节点) ↓ Node → DOM 树 2.2 遇到资源时的行为 标签 行为 是否阻塞 HTML 解析 <script> 下载 + 执行 ✅ 阻塞(脚本会操作 DOM) ...
Okhttp框架介绍
OkHttp 是由 Square 公司开源的一个高性能 HTTP 客户端,是目前 Java 和 Android 生态中最主流、事实上的网络请求标准库。Android 官方从 Android 4.4 起底层已将 HttpURLConnection 替换为 OkHttp 实现,而当下流行的 Retrofit 网络框架底层也是交由 OkHttp 负责真正的网络收发。 相比 JDK 自带的 HttpURLConnection 或早期的 Apache HttpClient,OkHttp 具有显著的优势: 性能卓越:原生支持 HTTP/2 协议(多路复用)和连接池,能够共享同一个 Socket 连接,大幅降低 TCP 握手开销与请求延迟。 自动处理:支持透明的 GZIP 压缩(自动压缩请求体并解压响应体,节省流量)、响应缓存(避免重复网络请求)、以及自动处理重定向和故障恢复。 API 简洁优雅:封装程度高,无需手动处理繁琐的流和状态码,代码量大幅减少,开发效率极高。 灵活的拦截器链:基于责任链设计模式,允许开发者轻松插拔日志记录、统一 Token 注入、签名校验、失败重试等功能...
组件化开发
什么是组件化? 在项目开发中往往根据功能的不同划分多个模块,在小型项目中大家往往会把各模块放置到对应的包当中,这样是很方便,小编也喜欢这样干。但是,划重点!是“小”项目中,要是大项目还是按包来划分后期改动的时候会不会牵一发而动全身呢?会的。所以组件化登场了,将每个功能分成独立模块,模块之间独立性强却有些许联系。如此,我们在更改代码时就不会遇到前面所说的困扰了。下面,我上一份图来帮助大家理解。 app壳工程 模块之间相互独立,那就需要一个“主子”来统筹全局,那就是app壳工程 业务组件化 这就是各个功能模块,比如用户注册登录、首页、个人等等 公共基础库 这里集成着项目中每个或多个模块需要的基础功能,也就是共享库。比如基本数据、网络访问框架、Application(的context)、工具类Utils。 组件化优势 层次分明,即使是另一个人接手项目也能清晰项目框架,很快入手项目 拆卸方便,某个模块不想要了或者要替换成另一个模块,直接拆卸即可,只需要做很小的改动 不相互依赖,前面提到过,依赖性太强会导致改动太大 重复利用 集成环境/组件环境部署配置创建新...
开发技巧(一)
前言 本章,小编来介绍一些省时省力的开发技巧,都是从前辈那学来的。平时做些小demo还感觉不到这些技巧的实用性,当遇到大项目时就感觉真香。 全局获取Context的技巧 我们在Android开发中难免会用到context,到底传哪个context呢?在Activity这样的类中可以传this(Activity自己就是个context),在自己创建的类中通过外部传入context,那这个context是谁?是Activity?最好不要这样,除非是涉及到跳转(这种情况只能用Activity),为什么呢?先看代码技巧,我再娓娓道来。 Android提供了一个Application类,每当程序启动的时候,系统就会自动将这个类进行初始化。而我们可以定制一个自己的Application类,以便于管理程序内一些全局的状态信息,比如全局Context。 class SkinApplication: Application() { companion object{ @SuppressLint("StaticFieldLeak") ...
Activity生命周期与启动模式
前言 今天,小编来聊一聊我们的“老朋友”Activity,我相信作为一个Android开发爱好者,Activity是大家最熟悉的和打交道最多的。今天,我们就来细解Activity的生命周期与启动模式,最后再来介绍一下Activity的最佳实践方式。 Activity的生命周期返回栈Android由任务(Task)来管理Activity,一个任务就是一组存放在栈里的Activity的集合,这个栈也被称为返回栈(back stack)。栈是一种后进先出的数据结构,在默认情况下,每当我们启动了一个新的Activity,他就会在返回栈中入栈,并处于栈顶的位置。而每当我们按下Back键或调用finish()方法去销毁一个Activity时,处于栈顶的Activity就会出栈,前一个入栈的Activity就会重新处于栈顶的位置。系统总是会显示处于栈顶的Activity给用户。 Activity的状态每一个Activity在其生命周期中最多会有4种状态。 运行状态 当一个Activity位于返回栈的顶部时,Activity就处于运行状态。系统最不愿意回收的就是处于运行状态的Activity...
Android广播机制
前言 就像计算机网络中的广播一样,我们的Android中也存在类似的广播机制,并且Android中的广播机制更加灵活。 广播机制简介 Android中的每个应用程序都可以对自己感兴趣的广播进行注册,这样改程序就只会收到自己关心的广播内容,这些广播可能是来自于系统的,也可能是来自于其他应用程序的。Android提供了一套完整的API,允许应用程序自由地发送和接收广播。发送广播的方式就是我们熟知的Intent,而接收广播的主角就是四大组件之一的BroadcastReceiver。 Android内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息。比如手机开机完成后会发出一条广播,电池的电量变化会发出一条广播,系统时间发生改变也会发出一条广播,等等。 广播主要有两种类型 标准广播:一种完全异步执行的广播,在发送广播之后,所有的BroadcastReceiver几乎会在同一时刻收到这条广播信息,因此它们之间没有任何先后顺序可言。 有序广播:一种同步执行的广播,在广播发出之后,同一时刻只会有一个BroadcastReceiver能够收到这条广播信...
通知的创建
前言 小编在前面讲Service的时候用到了通知,还记得我们用来干嘛吗?没错,为了在程序退到后台后前台依然知道该程序的存在,在音乐、地图等APP非常常见。 通知是啥?拿起你的智能机,下拉一下通知栏。看到了吧! 但是,通知的设计初衷是好的,后来却被开发者玩坏了。 开发者为了增加自己的应用程序的打开率,发送各种各样的通知以博取更多的展示机会。作为用户的我们对这些垃圾信息非常厌恶。 虽然Android系统允许我们将某个应用程序的通知完全屏蔽,以防止它一直给我们发送垃圾信息,但是在这些信息中,也可能会有我们关心的内容。比如说我希望收到某个我关注的人的微博更新的消息,但是却不想微博一天到晚给我推一些垃圾信息。再过去,用户没有办法对这些信息做区分,要么同意接受所有信息,要么屏蔽所有信息,这也是Android通知功能的痛点。后来…… 通知渠道后来,Android8.0之后引入了通知渠道。 通知渠道就是每条通知都要属于一个对应的渠道。每个应用都可以自由地创建当前应用的通知渠道,但是这些通知渠道的控制权是掌握在用户手上的。用户可以自由地选择这些通知渠道的重要程度,是否响铃、是否振动或者是否要关...
APP卡顿与布局优化
前言大多数用户感知到的卡顿等性能问题的主要根源都是因为渲染性能。Android系统每隔大概16.6ms发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,这样就能达到流畅的画面所需要的60fps,为了能够实现fps(每秒传输帧数),这意味着程序的大多数操作都必须在16ms完成。 我们通常都会提到60fps和16ms,可是知道为何会以程序是否达到60fps来作为APP性能的衡量标准吗?这是因为人眼与大脑之间的协作无法感知超过60fps的画面更新。 12fps大概类似手动快速翻动书籍的频率,这明显是可以感知到是不够顺滑的。24fps使得人眼感知的是连续线性的运动,这其实是归功于运动模糊的效果。24fps是电影胶圈通常使用的帧率,因为这个帧率已经足够支撑大部分电影画面需要表达的内容,同时能够最大的减少费用的支出。但是低于30fps是无法顺畅表现绚丽的画面的内容的,此时就需要用到60fps来表达想要的效果,当然超过60fps是没有必要的。开发app的性能目标就是保持60fps,这意味着每一帧你只有16ms=1000/60的时间来处理事务。 如果某个操作花费时...
Android APP启动优化
启动状态应用有三种启动状态,每种状态都会影响应用向用户显示所需的时间;冷启动、温启动和热启动。在冷启动中,应用从头开始启动。在另外两种状态中,系统需要将后台的应用带入前台。建议始终在假定冷启动的基础上进行优化。这样做也可以提升温启动和热启动的性能。 冷启动 冷启动是指应用从头开始启动;系统进程在冷启动后才创建应用进程。发生冷启动的情况包括自设备启动后或系统终止应用后首次启动。 热启动 在热启动中,系统的所有工作就是将Activity带到前台。只有应用的所有Activity仍驻留在内存中,应用就不必重复执行对象初始化、布局加载和绘制。 温启动 温启动包含了在冷启动期间发生的部分操作;同时,它的开销要比热启动高。有潜在状态可视为温启动。例如: 用户在退出应用后又重新启动应用。进程可能未被销毁,继续运行,但应用需要执行onCreate()从头开始创建Activity。 系统将应用从内存释放,然后用户又重新启动它。进程和Activity需要重新启动,但传递到onCreate()的已保存的实例state bundle对于完成此任务有一定助益。 冷启动耗时统计在性能测试中...
深入理解并发编程和归纳总结
AQS什么是AQSAbstractQueueSynchronizer(抽象队列同步器) 是用来构建锁和其他同步组件的基础架构,比如ReentrantLock、ReetrantReadWriteLock和CountDownLatch就是基于AQS实现的。它使用一个int成员变量state标识同步状态,通过内置的FIFO(队列)来完成获取资源线程的排队工作。它是CLH队列锁的一种变体实现。它可以实现两种同步方式:独占式、共享式。AQS的主要使用方式是继承,子类通过继承AQS并实现它的抽象方式来管理同步状态,同步器的设计基于模板方法模式,所以如果要实现我们自己的同步工具类就需要其中几个可重写的方法,如tryAcquire、tryRelease、tryReleaseShared等等。这样设计的目的是同步组件(比如锁)是面向使用者的,它定义了使用者和同步组件交互的接口(比如可以允许两个线程并访问),隐藏了实现细节;同步器面向的是锁的实现者,它简化了锁的实现方式,屏蔽了同步状态管理、线程的排队、等待与唤醒等底层操作。这样就很好地隔离了使用者和实现者锁需关注的领域。在内部,AQS维护一个共享...








