当前位置: 首页 > news >正文

深入理解Android WebView的加载流程与事件回调

文章目录

    • 一、WebView 加载流程时序图
    • 二、WebView 加载流程回调函数说明
    • 三、`AwContents`
      • 3.1 主要功能和职责
      • 3.2 架构和实现
      • 3.3 使用场景
    • 四、利用WebView回调函数检测白屏
      • 4.1 使用`onPageStarted`和`onPageFinished`检测加载时间
      • 4.2 利用`onReceivedError`和`onReceivedHttpError`检测加载错误
      • 4.3 使用`shouldInterceptRequest`监控资源加载
      • 4.4 使用`onPageCommitVisible`
      • 4.5 结合JavaScript和`evaluateJavascript`
    • 五、结论

在Android开发中,WebView用于显示网页和执行JavaScript。理解其加载流程和事件回调对于开发一个功能丰富且用户友好的基于Web的应用至关重要。本文将详细介绍 WebView 加载一个URL时的整个流程和相关的事件回调,帮助开发者更好地掌握其使用方法和处理可能出现的问题。

一、WebView 加载流程时序图

当用户通过 WebView 加载一个URL时,整个过程涉及多个组件和一系列复杂的交互。下面是一个 WebView 加载URL的时序图,以及对每个回调事件的详细说明。

用户 WebView WebViewClient Native层 (AwContents) loadUrl() nativeLoadUrl() 页面加载开始 onPageStarted() 页面开始加载时调用,通知应用页面加载已经开始。 shouldInterceptRequest (多次) WebView每次请求资源时调用,允许应用拦截、修改或替换资源请求。 onLoadResource (多次) 加载页面资源时调用,通知应用页面资源正在加载。 onFormResubmission() 用户尝试重新提交表单时调用,询问用户是否重新提交表单。 onReceivedHttpAuthRequest() 需要HTTP认证时调用,请求HTTP认证信息。 onReceivedClientCertRequest() 服务器请求客户端证书时调用,提供客户端证书。 onReceivedSslError() SSL验证失败时调用,处理SSL错误。 onReceivedHttpError() HTTP错误响应时调用,处理HTTP错误。 onTooManyRedirects() 页面重定向过多时调用,处理重定向问题。 onSafeBrowsingHit() 访问到被谷歌标记为不安全的网页时调用,处理安全浏览警告。 shouldOverrideUrlLoading() WebView即将加载某个URL时调用,决定是否由应用而非WebView处理该URL。 shouldOverrideKeyEvent() onUnhandledKeyEvent() onScaleChanged() onPageCommitVisible() 页面内容即将显示时调用,通知页面内容即将可见。 页面开始显示 onPageFinished() 页面加载完成时调用,通知应用页面加载已经完成。 页面加载完成 用户 WebView WebViewClient Native层 (AwContents)

上面的时序图提供了一个清晰的视图,展示了从开始加载URL到页面加载完成的整个过程中WebView和WebViewClient的交互。每个回调都在特定的时机被触发,以处理不同的事件和状态变化。

二、WebView 加载流程回调函数说明

在这里插入图片描述

  1. 触发加载
    用户或应用触发 loadUrl() 方法,开始加载指定的URL。

  2. 原生层处理
    WebView 调用其底层实现(通常是 AwContentsnativeLoadUrl() 方法)来开始网络请求。

  3. 页面加载的各阶段

  • 页面加载开始:此时,WebViewClientonPageStarted() 方法被调用,标志着页面加载的开始。
  • 资源请求拦截shouldInterceptRequest() 方法可能会被多次调用,允许开发者拦截、修改或替换正在加载的资源。
  • 资源加载:对于页面上的每个资源(如图片、CSS文件等),onLoadResource() 方法会被调用。
  1. 处理特殊事件
    在加载过程中,WebView 可能会遇到各种需要特殊处理的情况:
  • 表单重提交onFormResubmission() 被调用,询问用户是否重新提交表单。
  • HTTP认证请求onReceivedHttpAuthRequest() 请求HTTP认证信息。
  • 客户端证书请求onReceivedClientCertRequest() 提供客户端证书。
  • SSL错误处理onReceivedSslError() 处理SSL验证失败的情况。
  • HTTP错误处理onReceivedHttpError() 处理HTTP错误响应。
  • 重定向过多onTooManyRedirects() 处理页面重定向问题。
  • 安全浏览命中onSafeBrowsingHit() 处理访问到被标记为不安全的网页。
  1. 页面内容显示
  • 页面即将可见onPageCommitVisible() 方法被调用,标志着页面内容即将显示在屏幕上。
  • 页面加载完成:最终,onPageFinished() 方法被调用,通知应用页面已完全加载。

每个回调方法都有其特定的用途,例如,shouldOverrideUrlLoading() 允许开发者决定是否拦截URL加载,而 onScaleChanged() 则用于处理缩放事件。正确处理这些回调可以极大地增强应用的功能性和用户体验。

三、AwContents

本节介绍时序图中的AwContentsAwContents 是 Android WebView 的一个核心组件,它在 Android WebView 架构中扮演着非常重要的角色。AwContents 是 Chromium 项目的一部分,它负责管理 WebView 的内容渲染和事件处理。在 Android 系统中,AwContents 作为 WebView 的底层实现,提供了与 Chromium 引擎的直接交互接口。

3.1 主要功能和职责

  1. 内容渲染
    AwContents 负责将网页内容渲染到 WebView 组件上。它使用 Chromium 的渲染引擎(Blink)来解析 HTML、CSS 和 JavaScript,确保网页内容能够正确显示。

  2. 事件处理
    它处理来自上层 WebView 和 WebViewClient 的各种事件和请求,如页面加载、资源请求、导航事件等,并将这些事件转发到 Chromium 引擎。

  3. JavaScript 交互
    AwContents 提供了与 JavaScript 代码交互的接口,允许 Android 应用与网页中的 JavaScript 代码进行通信。

  4. 安全和隐私
    它实现了多种安全措施,如同源策略、内容安全策略等,以保护用户的安全和隐私。

  5. 网络请求管理
    AwContents 管理所有网络请求,包括图片、CSS 文件、JavaScript 文件等资源的加载。它支持自定义网络请求的处理,例如通过 shouldInterceptRequest() 方法拦截和修改请求。

3.2 架构和实现

AwContents 是一个桥接类,它连接了 Android 的 WebView API 和 Chromium 的底层实现。在 Android WebView 的架构中,AwContents 位于 Java 层和 native 层之间,它通过 JNI(Java Native Interface)与 native 代码进行交互。

在 native 层,AwContents 对应的实现是 content::WebContents,这是 Chromium 中用于管理网页内容的核心类。WebContents 负责页面的生命周期管理、渲染进程管理和页面内容的实际渲染。

3.3 使用场景

开发者通常不直接与 AwContents 交互,而是通过 WebView 提供的高级 API 来进行开发。然而,了解 AwContents 的工作原理对于解决 WebView 中的高级问题、性能优化以及实现自定义功能非常有帮助。

AwContents 是 Android WebView 中的一个关键组件,它使得 WebView 能够利用 Chromium 引擎的强大功能,提供高性能和高兼容性的网页浏览体验。

四、利用WebView回调函数检测白屏

在Android开发中,使用WebView时偶尔会遇到白屏问题,这通常是由于网页加载不完全、资源加载失败或者JavaScript错误等原因引起的。利用WebView的回调函数可以帮助我们检测并诊断这种白屏问题。以下是一些策略和步骤,展示如何使用WebView的回调函数来检测白屏:

4.1 使用onPageStartedonPageFinished检测加载时间

白屏可能是因为页面加载时间过长。通过记录onPageStartedonPageFinished之间的时间差,可以判断页面是否在合理的时间内完成加载。

webView.setWebViewClient(new WebViewClient() {long startTime;@Overridepublic void onPageStarted(WebView view, String url, Bitmap favicon) {super.onPageStarted(view, url, favicon);startTime = System.currentTimeMillis();}@Overridepublic void onPageFinished(WebView view, String url) {super.onPageFinished(view, url);long loadTime = System.currentTimeMillis() - startTime;if (loadTime > ACCEPTABLE_LOAD_TIME) {// 记录或处理加载时间过长的情况}}
});

4.2 利用onReceivedErroronReceivedHttpError检测加载错误

这些回调函数可以帮助我们捕获在加载过程中发生的错误,这些错误可能会导致页面内容无法正确显示,从而出现白屏。

webView.setWebViewClient(new WebViewClient() {@Overridepublic void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {super.onReceivedError(view, request, error);// 处理加载错误}@Overridepublic void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {super.onReceivedHttpError(view, request, errorResponse);// 处理HTTP错误}
});

4.3 使用shouldInterceptRequest监控资源加载

如果关键资源(如CSS或JavaScript文件)加载失败,可能会导致页面显示不完整或白屏。通过shouldInterceptRequest可以监控这些资源的加载情况。

webView.setWebViewClient(new WebViewClient() {@Overridepublic WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {// 检查请求的资源,记录加载失败的资源return super.shouldInterceptRequest(view, request);}
});

4.4 使用onPageCommitVisible

onPageCommitVisible在页面内容即将显示时调用,如果在这个阶段页面内容为空或不完整,可能是一个白屏的迹象。但是,onPageCommitVisible回调本身并不能直接提供页面内容的信息,我们需要结合其他方法来实现这个目标。一种可能的方法是在onPageCommitVisible回调中使用evaluateJavascript来检查页面的DOM结构。例如,我们可以检查某个关键元素是否存在,或者是否有内容。以下是一个示例:

webView.setWebViewClient(new WebViewClient() {@Overridepublic void onPageCommitVisible(WebView view, String url) {super.onPageCommitVisible(view, url);// 检查页面内容是否可见或部分内容是否缺失view.evaluateJavascript("(function() { return document.getElementById('keyElement').innerHTML; })();", new ValueCallback<String>() {@Overridepublic void onReceiveValue(String value) {if (value == null || value.isEmpty()) {// 如果关键元素不存在或没有内容,那么可能存在白屏问题Log.e("WebView", "Key element is missing or empty");}}});}
});

在这个示例中,我们假设keyElement是页面中的一个关键元素,我们通过JavaScript代码获取这个元素的内容,然后在回调中检查这个内容是否存在。如果不存在,那么可能存在白屏问题。

实际的检查方法可能需要根据你的具体需求进行调整。例如,你可能需要检查多个元素,或者使用更复杂的JavaScript代码来检查页面的状态。

4.5 结合JavaScript和evaluateJavascript

通过注入JavaScript代码检查DOM元素的存在或内容,可以帮助确认页面是否正确渲染。

webView.evaluateJavascript("(function() { return document.body.innerHTML; })();", new ValueCallback<String>() {@Overridepublic void onReceiveValue(String html) {if (html.isEmpty()) {// 处理白屏情况}}
});

通过上述方法,结合日志记录和异常处理机制,可以有效地检测和诊断WebView中的白屏问题。这些技术不仅可以帮助开发者提高应用的稳定性和用户体验,还可以在开发和测试阶段快速定位问题。

五、结论

WebView 的加载流程涉及复杂的交互和多个阶段,每个阶段都可能触发不同的事件回调。作为开发者,理解这些过程和回调的时机及其作用是非常重要的。这不仅可以帮助我们更有效地使用 WebView,还可以在开发过程中预见并解决潜在问题,从而创建更加稳定和可靠的应用。

相关文章:

深入理解Android WebView的加载流程与事件回调

文章目录 一、WebView 加载流程时序图二、WebView 加载流程回调函数说明三、AwContents3.1 主要功能和职责3.2 架构和实现3.3 使用场景 四、利用WebView回调函数检测白屏4.1 使用onPageStarted和onPageFinished检测加载时间4.2 利用onReceivedError和onReceivedHttpError检测加…...

机器视觉相机自动对焦算法

第一&#xff0c;Brenner梯度法、 第二&#xff0c;Tenegrad梯度法、 第三&#xff0c;laplace梯度法、 第四&#xff0c;方差法、 第五&#xff0c;能量梯度法。 此实例通过使用Halcon实现5种清晰度算法函数&#xff1a; 1. 方差算法函数&#xff1b; 2. 拉普拉斯能量函数…...

StarTowerChain:开启去中心化创新篇章

官网&#xff1a; www.startower.fr 在当今创新驱动的时代&#xff0c;StarTowerChain 以其独特的去中心化创新模式&#xff0c;为我们带来了新的希望和机遇。去中心化&#xff0c;这个充满活力与创造力的理念&#xff0c;正引领着我们走向未来的创新之路。 StarTowerChain …...

SpringCloudStream使用StreamBridge实现延时队列

利用RabbitMQ实现消息的延迟队列 一、安装RabbitMQ 1、安装rabbitmq 安装可以看https://blog.csdn.net/qq_38618691/article/details/118223851,进行安装。 2、安装插件 安装完毕后,exchange是不支持延迟类型的,需要手动安装插件,需要和安装的rabbitmq版本一致 https:…...

MATLAB中head函数用法

目录 语法 说明 示例 显示矩阵的前八行 显示表的前三行 返回表的前八行 head函数的功能是获取数组或表的顶行。 语法 head(A) head(A,k) B head(___) 说明 head(A) 在命令行窗口中显示数组、表或时间表 A 的前八行&#xff0c;但不存储值。 head(A,k) 显示 A 的前 k …...

golang 基本数据类型

1. go语言的数据类型简介 golang的数据类型分为两大类&#xff0c;一类是基本数据类型和符合数据类型&#xff1b; 按照传递的内容分&#xff1a;传递本身数据和传递地址&#xff1b; golang和java很相似&#xff0c;都是值传递&#xff0c;不过分为传递的值和传递的地址&a…...

各种查询sql介绍

1. 关联查询&#xff08;JOIN&#xff09; 关联查询用于从多个表中检索数据。它基于两个或多个表之间的共同字段&#xff08;通常是主键和外键&#xff09;来组合数据。 内连接&#xff08;INNER JOIN&#xff09;&#xff1a; sql SELECT a.name, b.order_date FROM custome…...

Guava防击穿回源-异步防击穿

异步防击穿策略 在高并发环境下,缓存击穿(Cache Stampede)是一种常见的问题。当缓存中的热点数据失效或未命中时,大量并发请求同时访问后端数据源(如数据库),可能导致后端系统压力骤增,甚至出现崩溃。为了有效防止这种情况,可以利用Guava提供的异步缓存加载机制(类似…...

人工智能正在扼杀云计算的可持续性

可持续性曾是公共云计算中备受推崇的优势。企业和云提供商大肆宣扬他们的绿色计划&#xff0c;推广采用可再生能源的数据中心&#xff0c;以减少碳足迹。 近几个月来&#xff0c;这个话题已悄然淡出人们的视线。罪魁祸首是什么&#xff1f;对人工智能功能的无限需求正在推动云…...

C# 条形码、二维码标签打印程序

1、条码标答打印主界面 2、打印设置 3、生成QR代码 private void GetBarcode_T(string lr) { QRCodeEncoder qrCodeEncoder = new QRCodeEncoder();//创建一个对象 qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE; //设置编码测量…...

嵌入式入门学习——6Protues点亮数码管,认识位码和段码,分辨共阴还是共阳(数字时钟第一步)

0 系列文章入口 嵌入式入门学习——0快速入门&#xff0c;Let‘s Do It&#xff01; 首先新建基于Arduino UNO的protues工程&#xff0c;见本系列第3篇文章 1 点“P”按钮找器件 2 输入“seg”或“digit”查找数码管器件 3 找到我们想要的6位7段数码管 4如图A、B…DP都是段码…...

poisson过程——随机模拟(Python和R实现)

Python实现 exponential()使用&#xff0c;自动poisson过程实现。 import numpy as np import matplotlib.pyplot as plt# Parameters lambda_rate 5 # rate parameter (events per time unit) T 10 # total time# Generate Poisson process times np.random.exponential(…...

100 种下划线 / 覆盖层动画 | 终极 CSS(层叠样式表)集合

还在为你的菜单项和链接寻找动画效果而感到疲惫吗&#xff1f; 不用再找了&#xff01;这里列出了 100 多种不同的动画。从简单的到更复杂的&#xff0c;你肯定能找到自己想要的。 无需 SVG&#xff08;可缩放矢量图形&#xff09;&#xff0c;无需 JavaScript&#xff08;脚…...

华为ICT大赛2024-2025网络赛道考试分析

华为ICT大赛2024-2025正在报名中&#xff0c;网络赛道的同学如何备考&#xff0c;了解考试内容呢&#xff1f; 一、考试概况 华为ICT大赛分为4个赛段&#xff0c;分别为省赛初赛、省赛复赛、中国总决赛&#xff0c;全球总决赛。其中对应的能力级别分别如下&#xff1a; 省赛…...

linux 效率化 - 输入法 - fcitx5

安装 Fcitx5 1. 卸载 ibus 框架 由于 ibus 和 fcitx 可能会冲突&#xff0c;先卸载 ibus&#xff08;暂未确认原因&#xff09; sudo apt remove --purge ibus2. 安装 fcitx5 输入法框架 sudo apt update sudo apt install fcitx5 fcitx5-chinese-addons fcitx5-frontend-gtk…...

YOLOv11改进策略【卷积层】| 替换骨干网络 CVPR-2024 RepViT 轻量级的Vision Transformers架构

一、本文介绍 本文记录的是基于RepVit的YOLOv11轻量化改进方法研究。RepVit的网络结构借鉴ViT的设计理念,通过分离的token mixe和channel mixer减少推理时的计算和内存成本,同时减少扩展比率并增加宽度,降低延迟,并通过加倍通道来弥补参数大幅减少的问题,提高了准确性。本…...

一天认识一个硬件之路由器

今天来给大家分享一下路由器的知识&#xff0c;先来说一下什么是路由器&#xff0c;路由器是一种计算机网络设备&#xff0c;它的主要作用是在不同的网络之间转发数据包&#xff0c;实现数据的传输和共享&#xff0c;介绍完了什么是路由器&#xff0c;再来介绍一下路由器的定义…...

【scene_manager】与 MoveIt 机器人的规划场景进行交互

scene_manager Scene Manager包是由 Robotnik 创建的 ROS 包&#xff0c;旨在帮助构建和与 MoveIt 机器人的规划场景进行交互。 背景信息 MoveIt 规划场景 是一个用于存储机器人周围世界的表示&#xff08;外部碰撞&#xff09;以及机器人自身状态&#xff08;内部碰撞和当…...

数据结构单向链表的插入和删除(一)

链表 一、链表结构&#xff1a; &#xff08;物理存储结构上不连续&#xff0c;逻辑上连续&#xff1b;大小不固定&#xff09;二、单链表&#xff1a;三、单项链表的代码实现&#xff1a;四、开发可用的链表&#xff1a;四、单链表的效率分析&#xff1a; 一、链表结构&#x…...

鸿蒙网络编程系列30-断点续传下载文件示例

1. 断点续传简介 在文件的下载中&#xff0c;特别是大文件的下载中&#xff0c;可能会出现各种原因导致的下载暂停情况&#xff0c;如果不做特殊处理&#xff0c;下次还需要从头开始下载&#xff0c;既浪费了时间&#xff0c;又浪费了流量。不过&#xff0c;HTTP协议通过Range…...

深入拆解TomcatJetty(二)

深入拆解Tomcat&Jetty&#xff08;二&#xff09; 专栏地址&#xff1a;https://time.geekbang.org/column/intro/100027701 1、Tomcat支持的IO模型和应用层协议 IO模型&#xff1a; NIO&#xff1a;非阻塞 I/O&#xff0c;采用 Java NIO 类库实现。NIO2&#xff1a;异…...

单元化架构,分布式系统的新王!

0 关键收获 单元化架构通过减少故障的爆炸半径来增加系统弹性单元化架构是那些任何停机时间都被认为是不可接受的&#xff0c;或者可以显著影响最终用户的系统的一个好选择单元化架构通过强制使用固定大小的单元作为部署单元&#xff0c;并倾向于扩展而不是扩展的方法&#xf…...

【力扣打卡系列】滑动窗口与双指针(乘积小于K的子数组)

坚持按题型打卡&刷&梳理力扣算法题系列&#xff0c;语言为go&#xff0c;Day6 乘积小于K的子数组 题目描述解题思路 双指针移动&#xff0c;遍历右端点right&#xff0c;滑动左端点left子数组的个数&#xff1a;固定右端点r&#xff0c;子数组的个数其实就是从l到r的元…...

浅谈微前端【qiankun】的应用

一、为什么要使用微前端 微前端的核心理念是将一个大型的单体前端应用拆分成多个独立的小型应用&#xff0c;以便各个应用能够独立开发、部署和更新。这带来了以下几个好处&#xff1a; 独立开发与部署&#xff1a;各个团队可以独立开发自己的子应用&#xff0c;快速上线新功能…...

【JavaEE】——四次挥手,TCP状态转换,滑动窗口,流量控制

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;断开连接的本质 二&#xff1a;四次挥手 1&#xff1a;FIN 2&#xff1a;过程梳理 …...

D42【python 接口自动化学习】- python基础之函数

day42 高阶函数 学习日期&#xff1a;20241019 学习目标&#xff1a;函数&#xfe63;- 55 高阶函数&#xff1a;函数对象与函数调用的用法区别 学习笔记&#xff1a; 函数对象和函数调用 # 函数对象和函数调用 def foo():print(foo display)# 函数对象 a foo print(a) # &…...

GitLab 老旧版本如何升级?

极狐GitLab 正式对外推出 GitLab 专业升级服务 https://dl.gitlab.cn/cm33bsfv&#xff01; 专业的技术人员为您的 GitLab 老旧版本实例进行专业升级&#xff01;服务详情可以在官网查看详细解读&#xff01; 那些因为老旧版本而被攻击的例子 话不多说&#xff0c;直接上图&a…...

现今 CSS3 最强二维布局系统 Grid 网格布局

深入学习 CSS3 目前最强大的布局系统 Grid 网格布局 Grid 网格布局的基本认识 Grid 网格布局: Grid 布局是一个基于网格的二位布局系统&#xff0c;是目前 CSS 最强的布局系统&#xff0c;它可以同时对列和行进行处理&#xff08;它将网页划分成一个个网格&#xff0c;可以任…...

【图解版】力扣第146题:LRU缓存

力扣第146题&#xff1a;LRU缓存 一、LRU算法1. 基本概念2. LRU 和 LFU 的区别&#xff1a;3. 为什么 LRU 不需要记录使用频率&#xff1f; 二、Golang代码实现三、代码图解1. LRUCache、DLinkedNode两个结构体2. 初始化结构体对象3. addToHead函数4. removeNode函数5. moveToH…...

数据库知识点整理

DDL DDL-数据库操作 show databases ------------ 查看所有数据库 select database(); ----------查看当前数据库 create database 数据库名&#xff1b;---- 创建数据库 use 数据库名&#xff1b; --------------使用数据库 drop database 数据库名&#xff1b;--…...