WebViewCompat.navigate เป็นตัวเลือกที่ได้รับการปรับปรุงให้ดีขึ้นแทน
WebView.loadUrl ซึ่งช่วยให้คุณควบคุมการโหลดหน้าเว็บ การจัดการประวัติ และการติดตามวงจรการนำทางใน WebView ได้อย่างละเอียด
ก่อนหน้านี้ การเริ่มการนำทางหน้าเว็บโดยใช้ loadUrl มีข้อจำกัดที่สำคัญดังนี้
- ไม่มีการแทนที่รายการประวัติ: คุณไม่สามารถแทนที่รายการประวัติปัจจุบันได้ ทำให้ไม่สามารถไปยังหน้าใหม่ได้โดยไม่ต้องเพิ่มรายการลงในสแต็กย้อนกลับ
- การเรียกกลับที่แยกกัน: ไม่มีกลไกโดยตรงในการเชื่อมโยงการเรียก
loadUrlที่เฉพาะเจาะจงกับเหตุการณ์การเรียกกลับที่ตามมาในWebViewClient - ไม่ได้บันทึกส่วนหัวเพิ่มเติม: ระบบไม่ได้บันทึกส่วนหัวที่กำหนดเองที่ส่งไปยัง
loadUrlเป็นส่วนหนึ่งของสถานะWebViewดังนั้นส่วนหัวจึงหายไปเมื่อกู้คืนสถานะ
API WebViewCompat.navigate แก้ปัญหาเหล่านี้ด้วยการนำฟีเจอร์ต่อไปนี้มาใช้
- การแทนที่รายการประวัติการนำทาง: ช่วยให้คุณแทนที่หน้าปัจจุบันในสแต็กประวัติของ
WebViewได้ - การติดตามการเรียกกลับที่เชื่อมโยง: ส่งคืนออบเจ็กต์
Navigationซึ่ง ทำหน้าที่เป็นตัวระบุที่ไม่ซ้ำกันในทุกขั้นตอนของวงจรการนำทาง - การรองรับส่วนหัวของสถานะที่บันทึกไว้: ระบบจะบันทึกส่วนหัวเพิ่มเติมไว้ในบันเดิลสถานะของ
WebViewอย่างน่าเชื่อถือ เพื่อให้สามารถนำส่วนหัวเหล่านั้นกลับมาใช้ใหม่ได้เมื่อกู้คืนสถานะ
ความสามารถและข้อจำกัดที่สำคัญ
โปรดพิจารณากฎและการจำกัดการทำงานต่อไปนี้ก่อนนำ WebViewCompat.navigate ไปใช้
ความปลอดภัยของเธรด: คุณต้องเรียกใช้
WebViewCompat.navigateในเธรด UI (หลัก)การยกเลิกและการจัดลำดับความสำคัญ: คุณไม่สามารถยกเลิกการนำทางที่กำลังดำเนินการอยู่ได้อย่างชัดเจน อย่างไรก็ตาม การเริ่มการเรียก
navigateใหม่ในWebViewเดียวกันจะแทนที่การนำทางที่ใช้งานอยู่การรองรับสคีม URI: ระบบรองรับสคีม URI มาตรฐาน (เช่น
https:และhttp:) และสคีม URI ที่กำหนดเอง แต่ไม่รองรับรูปแบบjavascript:ขีดจำกัดขนาด URL: ความยาวสตริง URL สูงสุดที่รองรับคือ 2 MB
การตรวจสอบฟีเจอร์: ตรวจสอบความพร้อมใช้งานของฟีเจอร์โดยใช้
WebViewFeature.isFeatureSupportedเสมอก่อนเรียกใช้ API เพื่อ รักษาความเข้ากันได้ใน WebView APK เวอร์ชันต่างๆ
เริ่มการนำทางและติดตามวงจร
หากต้องการกำหนดค่าการนำทางและติดตามวงจรการนำทาง ให้ทำดังนี้
- ลงทะเบียนการใช้งาน
NavigationListenerโดยใช้WebViewCompat.addNavigationListenerระหว่างการตั้งค่าWebViewเพื่อรับ การเรียกกลับวงจรที่มีโครงสร้าง ลงทะเบียน Listener เพียงครั้งเดียว (แทนที่จะลงทะเบียนทุกครั้งที่เรียกใช้การนำทาง) เพื่อป้องกันการรั่วไหลของหน่วยความจำและการเรียกใช้การเรียกกลับซ้ำ - สร้างอินสแตนซ์
NavigationParametersโดยใช้NavigationParameters.Builderเพื่อระบุลักษณะการทำงานที่ไม่บังคับ เช่น การแทนที่ประวัติหรือส่วนหัว HTTP ที่กำหนดเอง - เรียกใช้
WebViewCompat.navigateโดยส่งอินสแตนซ์WebViewURL ปลายทาง และพารามิเตอร์
WebViewCompat.navigate จะส่งคืนออบเจ็กต์ Navigation ที่ระบุคำขอที่ไม่ซ้ำกัน
ในฟังก์ชันการเรียกกลับ NavigationListener ให้เปรียบเทียบ
ออบเจ็กต์นี้กับพารามิเตอร์ Navigation ที่เข้ามาเพื่อติดตามการนำทางที่เฉพาะเจาะจง
ตัวอย่างการใช้งาน
ตัวอย่างต่อไปนี้แสดงวิธีตั้งค่าพารามิเตอร์การนำทาง เรียกใช้ WebViewCompat.navigate และรับฟังเหตุการณ์วงจรการนำทาง
Kotlin
class WebNavigationManager(private val webView: WebView) {
// Track the navigation instance returned by the API
private var currentNavigation: Navigation? = null
init {
// 1. Define listener to observe navigation lifecycle events
val listener = object : NavigationListener {
override fun onNavigationStarted(navigation: Navigation) {
if (navigation == currentNavigation) {
// Navigation started
}
}
override fun onNavigationRedirected(navigation: Navigation) {
if (navigation == currentNavigation) {
// Navigation encountered a redirect
}
}
override fun onNavigationCompleted(navigation: Navigation) {
if (navigation == currentNavigation) {
if (navigation.didCommit()) {
// Navigation committed successfully
} else if (navigation.didCommitErrorPage()) {
// Navigation committed an error page
val statusCode = navigation.statusCode
val error = navigation.webResourceError
}
}
}
override fun onFirstContentfulPaintMillis(page: Page, durationMillis: Long) {
// Match page with current navigation
if (page == currentNavigation?.page) {
// Page rendering started (First Contentful Paint achieved)
}
}
}
// 2. Register listener on the main thread
WebViewCompat.addNavigationListener(webView, listener)
}
@UiThread
fun navigateToPage(url: String) {
// Check feature availability
if (!WebViewFeature.isFeatureSupported(WebViewFeature.WEBVIEW_NAVIGATE_EXPERIMENTAL_V1)) {
// Fall back to standard loadUrl if navigate API is unavailable
webView.loadUrl(url)
return
}
// 3. Configure navigation parameters
val params = NavigationParameters.Builder()
.setShouldReplaceCurrentEntry(true)
.addAdditionalHeaders(
mapOf("X-Test-Navigate-Header" to "TestValue")
)
.build()
// 4. Initiate navigation on the UI thread
currentNavigation = WebViewCompat.navigate(webView, url, params)
}
}
Java
public class WebNavigationManager {
private Navigation mCurrentNavigation;
private final WebView mWebView;
public WebNavigationManager(@NonNull WebView webView) {
mWebView = webView;
setupListener();
}
private void setupListener() {
// 1. Define listener to observe navigation lifecycle events
NavigationListener listener = new NavigationListener() {
@Override
public void onNavigationStarted(@NonNull Navigation navigation) {
if (navigation.equals(mCurrentNavigation)) {
// Navigation started
}
}
@Override
public void onNavigationRedirected(@NonNull Navigation navigation) {
if (navigation.equals(mCurrentNavigation)) {
// Navigation encountered a redirect
}
}
@Override
public void onNavigationCompleted(@NonNull Navigation navigation) {
if (navigation.equals(mCurrentNavigation)) {
if (navigation.didCommit()) {
// Navigation committed successfully
} else if (navigation.didCommitErrorPage()) {
// Navigation committed an error page
int statusCode = navigation.getStatusCode();
WebResourceErrorCompat error = navigation.getWebResourceError();
}
}
}
@Override
public void onFirstContentfulPaintMillis(@NonNull Page page, long durationMillis) {
if (mCurrentNavigation != null && page.equals(mCurrentNavigation.getPage())) {
// Page rendering started (First Contentful Paint achieved)
}
}
};
// 2. Register listener on the main thread
WebViewCompat.addNavigationListener(mWebView, listener);
}
@UiThread
public void navigateToPage(@NonNull String url) {
// Check feature availability
if (!WebViewFeature.isFeatureSupported(WebViewFeature.WEBVIEW_NAVIGATE_EXPERIMENTAL_V1)) {
// Fall back to standard loadUrl if navigate API is unavailable
mWebView.loadUrl(url);
return;
}
// 3. Configure navigation parameters
NavigationParameters params = new NavigationParameters.Builder()
.setShouldReplaceCurrentEntry(true)
.addAdditionalHeaders(Collections.singletonMap(
"X-Test-Navigate-Header", "TestValue"
))
.build();
// 4. Initiate navigation on the UI thread
mCurrentNavigation = WebViewCompat.navigate(mWebView, url, params);
}
}
โหมดความล้มเหลวและการจัดการข้อผิดพลาด
API WebViewCompat.navigate มีกลไกที่แตกต่างกันสำหรับการจัดการข้อผิดพลาดในการกำหนดค่าและความล้มเหลวในการนำทางขณะรันไทม์
ข้อยกเว้นของอาร์กิวเมนต์ไม่ถูกต้อง
การส่งอาร์กิวเมนต์ไม่ถูกต้องจะทริกเกอร์ IllegalArgumentException แบบซิงโครนัส
สาเหตุที่พบบ่อยมีดังนี้
- การส่ง
nullสำหรับพารามิเตอร์ที่ไม่ใช่ Null ที่จำเป็น (webView,urlหรือparams) - การระบุรูปแบบ URL ที่ไม่รองรับ เช่น
javascript: - การส่งคีย์หรือค่าส่วนหัว HTTP ที่มีรูปแบบไม่ถูกต้องซึ่งไม่เป็นไปตามข้อกำหนด RFC 2616
ข้อผิดพลาดของกระบวนการนำทาง
หากเกิดความล้มเหลวระหว่างคำขอเครือข่ายหรือการโหลดหน้าเว็บ (เช่น รหัสสถานะ HTTP 404 ความล้มเหลวในการแปลง DNS หรือข้อผิดพลาด SSL) WebViewCompat.navigate จะยังคงส่งคืนออบเจ็กต์ Navigation ที่ถูกต้อง
เมื่อการนำทางเสร็จสิ้น ให้ตรวจสอบเมธอดต่อไปนี้ในอินสแตนซ์ Navigation
ภายในฟังก์ชันการเรียกกลับ onNavigationCompleted เพื่อวินิจฉัยความล้มเหลว
getStatusCode: ส่งคืนรหัสสถานะการตอบกลับ HTTP (เช่น404หรือ500)getWebResourceError: ส่งคืนWebResourceErrorCompatออบเจ็กต์ที่ให้รายละเอียดเกี่ยวกับข้อผิดพลาดของเครือข่าย เช่น การหมดเวลาการเชื่อมต่อหรือความล้มเหลวในการค้นหาโฮสต์didCommitErrorPage: ระบุว่าWebViewคอมมิตและแสดงหน้าข้อผิดพลาดแก่ผู้ใช้หรือไม่didCommit: ระบุว่าการนำทางคอมมิตไปยังหน้าเป้าหมายได้สำเร็จโดยไม่ถูกยกเลิกหรือไม่
การจัดการบันเดิลสถานะที่บันทึกไว้
เมื่อคุณส่งส่วนหัวเพิ่มเติมด้วย NavigationParameters WebView จะบันทึกส่วนหัวเหล่านี้ไว้ในบันเดิลสถานะที่บันทึกไว้ เพื่อให้สามารถนำส่วนหัวเหล่านั้นกลับมาใช้ใหม่ได้เมื่อกู้คืนสถานะ อย่างไรก็ตาม คอลเล็กชันส่วนหัวขนาดใหญ่อาจเพิ่มขนาดของ Bundle สถานะที่บันทึกไว้อย่างมาก
หากต้องการจำกัดขนาดบันเดิลเพื่อป้องกัน TransactionTooLargeException
ระหว่างการบันทึกสถานะ Android ให้ใช้ WebViewCompat.saveState เมธอดนี้ช่วยให้คุณกำหนดขีดจำกัดขนาดบันเดิลสูงสุดเป็นไบต์ และเลือกยกเว้นรายการประวัติไปข้างหน้าได้
Kotlin
// Save state with a maximum bundle size limit (for example, 64 KB)
val maxSizeBytes = 64 * 1024
val includeForwardState = false
val outState = Bundle()
WebViewCompat.saveState(webView, outState, maxSizeBytes, includeForwardState)
Java
// Save state with a maximum bundle size limit (for example, 64 KB)
int maxSizeBytes = 64 * 1024;
boolean includeForwardState = false;
Bundle outState = new Bundle();
WebViewCompat.saveState(webView, outState, maxSizeBytes, includeForwardState);
บันเดิลที่ได้จะยังคงเข้ากันได้กับเมธอด มาตรฐาน
WebView.restoreState
คำแนะนำในการย้ายข้อมูลและการใช้งาน
ปฏิบัติตามคำแนะนำต่อไปนี้เพื่อให้มั่นใจถึงประสิทธิภาพและความเสถียรสูงสุดเมื่อนำทางใน WebView
ย้ายข้อมูลจาก
loadUrlไปเป็นnavigate: ย้ายข้อมูลการเรียกWebView.loadUrlทั้งหมดที่เลิกใช้งานแล้วไปเป็นWebViewCompat.navigateวิธีนี้จะช่วยให้การจัดการประวัติเป็นไปอย่างสม่ำเสมอและมั่นใจได้ว่าระบบจะบันทึกส่วนหัวเป็นส่วนหนึ่งของสถานะที่บันทึกไว้เสมอตรวจสอบการรองรับฟีเจอร์เสมอ: ก่อนเรียกใช้ API ให้ยืนยันการรองรับขณะรันไทม์ด้วย
WebViewFeature.isFeatureSupportedเพื่อป้องกัน WebView เวอร์ชันเก่าเชื่อมโยงอินสแตนซ์การนำทาง: ใช้ออบเจ็กต์
Navigationที่ส่งคืนเพื่อแยกความแตกต่างของการนำทางพร้อมกันหรือกรองการเรียกกลับเมื่อจัดการอินสแตนซ์WebViewหลายรายการลงทะเบียน Listener เพียงครั้งเดียวระหว่างการเริ่มต้น: เนื่องจาก
WebViewCompat.addNavigationListenerจะเพิ่ม Listener แทนที่จะแทนที่ Listener ที่มีอยู่ ให้ลงทะเบียนNavigationListenerเพียงครั้งเดียวระหว่างWebViewการตั้งค่าเพื่อหลีกเลี่ยงการรั่วไหลของหน่วยความจำและการเรียกใช้การเรียกกลับซ้ำในการนำทางครั้งต่อๆ ไปตรวจสอบขนาดสถานะที่บันทึกไว้: เมื่อส่งเพย์โหลดส่วนหัวขนาดใหญ่ ให้ใช้
WebViewCompat.saveStateที่มีขอบเขตขนาดที่ชัดเจนเพื่อหลีกเลี่ยงการบันทึกข้อมูลสถานะมากเกินไป
แหล่งข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับความสามารถของเว็บแบบฝังและการเพิ่มประสิทธิภาพได้ที่คำแนะนำต่อไปนี้
- ลดความซับซ้อนในการใช้งาน WebView ด้วย Jetpack Webkit
- การโหลดแบบคาดเดาใน WebView
- เพิ่มประสิทธิภาพการเริ่มต้นใช้งาน WebView
- จัดการการสิ้นสุดกระบวนการแสดงผลของ WebView