จัดการสถานะ WebView อย่างมีประสิทธิภาพ

เมื่อจัดการวงจรการทำงานของแอป Android การรักษาข้อมูลสถานะของผู้ใช้ระหว่างการเรียกคืนทรัพยากรเบื้องหลังเป็นองค์ประกอบหลักของประสบการณ์การใช้งานที่ราบรื่น สำหรับแอปที่รวมขั้นตอนการทำงานของเว็บ WebView.saveState(Bundle) จะช่วยให้คุณแปลงข้อมูลประวัติการนำทางและสถานะของ WebView เป็น Bundle และสามารถกู้คืนข้อมูลนี้ได้ในภายหลังโดยใช้ WebView.restoreState(Bundle)

อย่างไรก็ตาม การใช้งานมาตรฐานอาจพบข้อจำกัดด้านขนาดธุรกรรมในระหว่างเซสชันการท่องเว็บที่มีการใช้งานสูง หน้านี้อธิบายข้อจำกัดทางสถาปัตยกรรมเหล่านี้และนำเสนอกลยุทธ์ในการป้องกันข้อยกเว้นที่เกี่ยวข้องกับหน่วยความจำในขณะที่ยังคงรักษาประวัติการนำทางไว้

ขีดจำกัดการทำธุรกรรม 1MB และการล้างข้อมูลสถานะ

Android กำหนดขีดจำกัดที่เข้มงวดไว้ที่ 1MB สำหรับปริมาณข้อมูลทั้งหมดที่จัดเก็บไว้ใน savedInstanceState งบประมาณ 1MB นี้ใช้ร่วมกันในกระบวนการของแอปทั้งหมด หากแอปมีอินสแตนซ์ WebView หลายรายการ สถานะและประวัติการนำทางโดยรวมของอินสแตนซ์เหล่านั้นต้องมีขนาดไม่เกินการจัดสรรที่ใช้ร่วมกันนี้ การเกินขีดจำกัดนี้จะทริกเกอร์ TransactionTooLargeException ซึ่งส่งผลให้แอปขัดข้อง

กลยุทธ์การลดผลกระทบที่พบได้ทั่วไปแต่มีปัญหาคือการตรวจสอบขนาดของ Bundle สถานะ WebView และล้างประวัติ WebView ทั้งหมดหากมีขนาดเกินเกณฑ์ความปลอดภัยที่กำหนด (เช่น 300KB) แม้ว่าวิธีนี้จะป้องกันไม่ให้แอปขัดข้อง แต่ก็ทำให้เกิดการถดถอยอย่างรุนแรงในประสบการณ์การใช้งานของผู้ใช้ ดังนี้

  • การนำทางย้อนกลับไม่ได้: Android มักจะยุติกระบวนการของแอปเบื้องหลัง เพื่อเรียกคืนหน่วยความจำสำหรับงานอื่นๆ คุณสามารถใช้ saveState(Bundle) ภายใน Lifecycle Callback onSaveInstanceState() เพื่อรักษาประวัติการนำทางไว้ หากคุณล้างประวัติการนำทางนี้เพื่อหลีกเลี่ยงขีดจำกัดการทำธุรกรรม 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 ประกอบด้วย BLOB PageState ภายในจากเครื่องมือแสดงผล ข้อมูลนี้จะบันทึกสถานะเซสชันแบบละเอียด รวมถึงข้อมูลที่ป้อนในแบบฟอร์มและตำแหน่งการเลื่อนของ iframe หลีกเลี่ยงการพยายามแยกวิเคราะห์หรือแยกส่วนแต่ละส่วนออกจาก BLOB เหล่านี้ด้วยตนเอง เนื่องจากอาจทำให้เกิดความเสี่ยงด้านความปลอดภัยอย่างรุนแรงและทำให้ความสมบูรณ์ของการกู้คืนเซสชันเสียหาย

  • การจัดการประวัติแบบละเอียด: WebBackForwardList API มาตรฐานไม่ รองรับการนำองค์ประกอบที่ผ่านมาแต่ละรายการออกโดยพลการ สำหรับการจัดการสถานะที่เข้มงวด คุณต้องใช้กลยุทธ์การตัดข้อมูลโดยใช้พารามิเตอร์ maxSizeBytes และ includeForwardState ภายใน WebViewCompat.saveState() เพื่อให้มั่นใจถึงความปลอดภัยทางสถาปัตยกรรม