เมื่อจัดการวงจรการทำงานของแอป Android การรักษาข้อมูลสถานะของผู้ใช้ระหว่างการเรียกคืนทรัพยากรเบื้องหลังเป็นองค์ประกอบหลักของประสบการณ์การใช้งานที่ราบรื่น สำหรับแอปที่รวมขั้นตอนการทำงานของเว็บ WebView.saveState(Bundle)
จะช่วยให้คุณแปลงข้อมูลประวัติการนำทางและสถานะของ WebView เป็น Bundle
และสามารถกู้คืนข้อมูลนี้ได้ในภายหลังโดยใช้ WebView.restoreState(Bundle)
อย่างไรก็ตาม การใช้งานมาตรฐานอาจพบข้อจำกัดด้านขนาดธุรกรรมในระหว่างเซสชันการท่องเว็บที่มีการใช้งานสูง หน้านี้อธิบายข้อจำกัดทางสถาปัตยกรรมเหล่านี้และนำเสนอกลยุทธ์ในการป้องกันข้อยกเว้นที่เกี่ยวข้องกับหน่วยความจำในขณะที่ยังคงรักษาประวัติการนำทางไว้
ขีดจำกัดการทำธุรกรรม 1MB และการล้างข้อมูลสถานะ
Android กำหนดขีดจำกัดที่เข้มงวดไว้ที่ 1MB สำหรับปริมาณข้อมูลทั้งหมดที่จัดเก็บไว้ใน savedInstanceState งบประมาณ 1MB นี้ใช้ร่วมกันในกระบวนการของแอปทั้งหมด หากแอปมีอินสแตนซ์ WebView หลายรายการ สถานะและประวัติการนำทางโดยรวมของอินสแตนซ์เหล่านั้นต้องมีขนาดไม่เกินการจัดสรรที่ใช้ร่วมกันนี้ การเกินขีดจำกัดนี้จะทริกเกอร์ TransactionTooLargeException ซึ่งส่งผลให้แอปขัดข้อง
กลยุทธ์การลดผลกระทบที่พบได้ทั่วไปแต่มีปัญหาคือการตรวจสอบขนาดของ Bundle สถานะ WebView และล้างประวัติ WebView ทั้งหมดหากมีขนาดเกินเกณฑ์ความปลอดภัยที่กำหนด (เช่น 300KB) แม้ว่าวิธีนี้จะป้องกันไม่ให้แอปขัดข้อง แต่ก็ทำให้เกิดการถดถอยอย่างรุนแรงในประสบการณ์การใช้งานของผู้ใช้ ดังนี้
การนำทางย้อนกลับไม่ได้: Android มักจะยุติกระบวนการของแอปเบื้องหลัง เพื่อเรียกคืนหน่วยความจำสำหรับงานอื่นๆ คุณสามารถใช้
saveState(Bundle)ภายใน Lifecycle CallbackonSaveInstanceState()เพื่อรักษาประวัติการนำทางไว้ หากคุณล้างประวัติการนำทางนี้เพื่อหลีกเลี่ยงขีดจำกัดการทำธุรกรรม 1MB สแต็กการนำทางทั้งหมดจะหายไป เมื่อผู้ใช้กลับมาที่แอป ปุ่มย้อนกลับของระบบจะออกจากคอมโพเนนต์หรือแอปทันที เนื่องจากไม่มีบริบทที่ผ่านมาเหลืออยู่เพื่อรองรับการนำทางย้อนกลับ ไม่ว่าการรีสตาร์ทกระบวนการจะเกิดขึ้นหรือไม่ก็ตามการทำให้ BFCache ไม่ถูกต้อง: การล้างประวัติจะป้องกันไม่ให้แอปใช้ Back-Forward Cache (BFCache) ซึ่งจะทำให้ไม่สามารถแสดง หน้าเว็บที่เข้าชมก่อนหน้านี้ได้ทันที
เวลาในการตอบสนองเพิ่มขึ้น: ผู้ใช้จะสูญเสียสถานะปัจจุบันภายใน WebView, ซึ่งต้องทำการนำทางและเริ่มต้นใหม่ทั้งหมด กระบวนการนี้จะเพิ่มค่าใช้จ่ายเครือข่ายและเวลาในการตอบสนองของธุรกรรมอย่างมาก
กลยุทธ์การลดผลกระทบทางสถาปัตยกรรม
หากต้องการป้องกันการขัดข้องของ TransactionTooLargeException โดยไม่ทำให้ประสบการณ์การใช้งานของผู้ใช้แย่ลงจากการลบประวัติทั้งหมด คุณต้องรักษาสมดุลที่เข้มงวดระหว่างการเก็บข้อมูลสถานะกับประสิทธิภาพของหน่วยความจำ การใช้กลยุทธ์การเพิ่มประสิทธิภาพต่อไปนี้จะช่วยให้คุณจัดการงบประมาณธุรกรรม 1MB ได้อย่างปลอดภัยในขณะที่ยังคงรักษาประวัติการนำทางที่สำคัญและความสมบูรณ์ของเซสชันไว้
บังคับใช้ขีดจำกัดขนาดในการแปลงข้อมูลสถานะเป็นอนุกรม
แทนที่จะล้างสแต็กการนำทางทั้งหมดเมื่อมีขนาดใหญ่เกินไป รูปแบบที่มีประสิทธิภาพมากกว่าคือการตัดข้อมูลที่ผ่านมา ดังนี้
นโยบายการตัดข้อมูลที่กำหนดเป้าหมาย: ใช้
WebViewCompat.saveState()เพื่อแปลงข้อมูลสถานะเป็นอนุกรมในขณะที่บังคับใช้ขีดจำกัดไบต์ที่เฉพาะเจาะจง (เช่นWebViewCompat.saveState(webView, outState, maxSizeBytes)) API นี้จะตัดรายการการนำทางที่เก่ากว่าออกตามลำดับโดยอัตโนมัติจนกว่าเพย์โหลดทั้งหมดจะมีขนาดไม่เกินการจัดสรรที่คุณกำหนด ที่สำคัญคือ API นี้จะตัดเฉพาะBundleที่แปลงข้อมูลเป็นอนุกรมโดยไม่แก้ไขหรือล้างประวัติการใช้งานของWebViewที่ใช้งานอยู่ ซึ่งจะทำให้การนำทางย้อนกลับทันทียังคงสมบูรณ์การนำรายการไปข้างหน้าออก: หากอินเทอร์เฟซของแอปพลิเคชันมีปุ่มย้อนกลับ แต่ไม่มีปุ่มนำทางไปข้างหน้าโดยเฉพาะ คุณสามารถทิ้งรายการการนำทางไปข้างหน้าทั้งหมดได้โดยตั้งค่า
saveStateพารามิเตอร์includeForwardStateของ API เป็นfalseซึ่งจะลดขนาดเพย์โหลดลงอย่างมากโดยไม่ส่งผลต่อเส้นทางการนำทางที่มีให้ผู้ใช้
จัดการเวลาในการตอบสนองของทรัพยากรด้วย HTTP Cache Quota API
แม้ว่า saveState จะจัดการขีดจำกัด Bundle 1MB สำหรับประวัติการนำทางชั่วคราว แต่ HTTP Cache Quota API จะให้การควบคุมทรัพยากรเว็บที่คงอยู่ (แคชดิสก์) ด้วยตนเองตามโปรไฟล์ ซึ่งจะสร้างความแตกต่างที่ชัดเจนระหว่างบริบทการนำทางระยะสั้นกับชิ้นงานที่แคชไว้ระยะยาว
การเลือกโควต้าที่เหมาะสมเกี่ยวข้องกับการแลกเปลี่ยนประสิทธิภาพ ดังนี้
- โควต้าที่สูงขึ้น จะปรับปรุงความพร้อมใช้งานแบบออฟไลน์และเวลาในการตอบสนองในการโหลดทรัพยากรโดยการเก็บชิ้นงานไว้ในดิสก์มากขึ้น
- โควต้าที่ต่ำลง จะลดขนาดดิสก์ของแอปและป้องกันการนำแคชของข้อมูลแอปที่สำคัญอื่นๆ ออกโดยระบบปฏิบัติการ
การตั้งค่าเหล่านี้จะคงอยู่เมื่อรีสตาร์ทแอปและต้องกำหนดค่าจากเธรดหลัก
การใช้งานต่อไปนี้แสดงวิธีกำหนดค่าโควต้าแคชดิสก์สำหรับโปรไฟล์เริ่มต้น
Kotlin
if (WebViewFeature.isFeatureSupported(WebViewFeature.MULTI_PROFILE) &&
WebViewFeature.isFeatureSupported(WebViewFeature.HTTP_CACHE)) {
val defaultProfile = ProfileStore.getInstance()
.getOrCreateProfile(Profile.DEFAULT_PROFILE_NAME)
val httpCache = defaultProfile.httpCache
// Set explicit cache size to 50MB (50 * 1024 * 1024 bytes)
httpCache.setQuotaBytes(50L * 1024 * 1024)
}
Java
if (WebViewFeature.isFeatureSupported(WebViewFeature.MULTI_PROFILE) &&
WebViewFeature.isFeatureSupported(WebViewFeature.HTTP_CACHE)) {
Profile defaultProfile = ProfileStore.getInstance()
.getOrCreateProfile(Profile.DEFAULT_PROFILE_NAME);
HttpCache httpCache = defaultProfile.getHttpCache();
// Set explicit cache size to 50MB (50 * 1024 * 1024 bytes)
httpCache.setQuotaBytes(50L * 1024 * 1024);
}
ดูข้อมูลเพิ่มเติมเกี่ยวกับกลยุทธ์การกำหนดขนาดโควต้า การจัดการวงจรการทำงาน และ ขอบเขตโปรไฟล์ได้ที่หัวข้อ จัดการโควต้าแคช HTTP ใน WebView
ข้อควรพิจารณาด้านประสิทธิภาพที่สำคัญ
ประเด็นต่อไปนี้เน้นข้อจำกัดทางเทคนิคและลักษณะการทำงานของข้อมูลภายในที่ควบคุมลักษณะการทำงานของสถานะ WebView
BLOB
PageStateที่ไม่โปร่งใส: ข้อมูลประมาณ 70% ที่จัดเก็บโดยsaveStateประกอบด้วย BLOBPageStateภายในจากเครื่องมือแสดงผล ข้อมูลนี้จะบันทึกสถานะเซสชันแบบละเอียด รวมถึงข้อมูลที่ป้อนในแบบฟอร์มและตำแหน่งการเลื่อนของ iframe หลีกเลี่ยงการพยายามแยกวิเคราะห์หรือแยกส่วนแต่ละส่วนออกจาก BLOB เหล่านี้ด้วยตนเอง เนื่องจากอาจทำให้เกิดความเสี่ยงด้านความปลอดภัยอย่างรุนแรงและทำให้ความสมบูรณ์ของการกู้คืนเซสชันเสียหายการจัดการประวัติแบบละเอียด:
WebBackForwardListAPI มาตรฐานไม่ รองรับการนำองค์ประกอบที่ผ่านมาแต่ละรายการออกโดยพลการ สำหรับการจัดการสถานะที่เข้มงวด คุณต้องใช้กลยุทธ์การตัดข้อมูลโดยใช้พารามิเตอร์maxSizeBytesและincludeForwardStateภายในWebViewCompat.saveState()เพื่อให้มั่นใจถึงความปลอดภัยทางสถาปัตยกรรม