หลีกเลี่ยงการดาวน์โหลดที่ไม่ได้เพิ่มประสิทธิภาพ

ผู้ใช้แอปบางรายอาจเข้าถึงอินเทอร์เน็ตได้เป็นช่วงๆ หรือมีข้อจำกัดเกี่ยวกับปริมาณข้อมูลที่ดาวน์โหลดลงในอุปกรณ์ได้ คุณสามารถกระตุ้นให้ผู้ใช้โต้ตอบกับแอปบ่อยขึ้นได้โดยการลดปริมาณข้อมูลที่แอปต้องดาวน์โหลด

วิธีพื้นฐานที่สุดในการลดการดาวน์โหลดคือการดาวน์โหลดเฉพาะสิ่งที่คุณต้องการ ในแง่ของข้อมูล หมายถึงการใช้ REST API ที่ช่วยให้คุณระบุเกณฑ์การค้นหาที่จำกัดข้อมูลที่แสดงผลโดยใช้พารามิเตอร์ เช่น เวลาของการอัปเดตครั้งล่าสุด

ในทำนองเดียวกัน เมื่อดาวน์โหลดรูปภาพ แนวทางปฏิบัติแนะนำคือลดขนาดรูปภาพฝั่งเซิร์ฟเวอร์ แทนที่จะดาวน์โหลดรูปภาพขนาดเต็มที่ลดขนาดลงในฝั่งไคลเอ็นต์

แคชการตอบกลับ HTTP

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

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

เพื่อไม่ให้การแคชส่งผลให้แอปแสดงข้อมูลที่ล้าสมัย ให้ใช้รหัสสถานะ HTTP และส่วนหัว ที่เหมาะสม เช่น ส่วนหัว ETag และ Last-Modified ซึ่งจะช่วยให้คุณกำหนดได้ว่าควรรีเฟรชเนื้อหาที่เกี่ยวข้องเมื่อใด เช่น

Kotlin

// url represents the website containing the content to place into the cache.
val conn: HttpsURLConnection = url.openConnection() as HttpsURLConnection
val currentTime: Long = System.currentTimeMillis()
val lastModified: Long = conn.getHeaderFieldDate("Last-Modified", currentTime)

// lastUpdateTime represents when the cache was last updated.
if (lastModified < lastUpdateTime) {
    // Skip update
} else {
    // Parse update
    lastUpdateTime = lastModified
}

Java

// url represents the website containing the content to place into the cache.
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
long currentTime = System.currentTimeMillis();
long lastModified = conn.getHeaderFieldDate("Last-Modified", currentTime);

// lastUpdateTime represents when the cache was last updated.
if (lastModified < lastUpdateTime) {
    // Skip update
} else {
    // Parse update
    lastUpdateTime = lastModified;
}

คุณสามารถกำหนดค่าไลบรารีเครือข่ายบางรายการให้ปฏิบัติตามรหัสสถานะและส่วนหัวเหล่านี้โดยอัตโนมัติ ตัวอย่างเช่น เมื่อใช้ OkHttp การกำหนดค่าไดเรกทอรีแคชและขนาดแคชสำหรับไคลเอ็นต์จะช่วยให้ไลบรารีใช้การแคช HTTP ได้ ดังที่แสดงในตัวอย่างโค้ดต่อไปนี้

Kotlin

val cacheDir = Context.getCacheDir()
val cacheSize = 10L * 1024L * 1024L // 10 MiB
val client: OkHttpClient = OkHttpClient.Builder()
    .cache(Cache(cacheDir, cacheSize))
    .build()

Java

File cacheDir = Context.getCacheDir();
long cacheSize = 10L * 1024L * 1024L; // 10 MiB
OkHttpClient client = new OkHttpClient.Builder()
    .cache(new Cache(cacheDir, cacheSize))
    .build();

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

คุณสามารถแคชข้อมูลที่ไม่ละเอียดอ่อนในไดเรกทอรีแคชภายนอกที่ไม่มีการจัดการได้โดยใช้ Context.getExternalCacheDir() หรือจะแคชข้อมูลในแคชของแอปพลิเคชันที่มีการจัดการและปลอดภัยโดยใช้ Context.getCacheDir() ก็ได้ โปรดทราบว่าระบบอาจล้างแคชภายในนี้เมื่อพื้นที่เก็บข้อมูลที่ใช้ได้เหลือน้อย

ใช้ที่เก็บ

หากต้องการใช้แนวทางการแคชที่ซับซ้อนมากขึ้น ให้ลองใช้รูปแบบการออกแบบที่เก็บ ซึ่งเป็นการสร้างคลาสที่กำหนดเองที่เรียกว่า Repository ซึ่งทำแอบสแตรกชันให้ API ในข้อมูลหรือทรัพยากรที่เฉพาะเจาะจง ที่เก็บอาจดึงข้อมูลจากแหล่งต่างๆ ในตอนแรก เช่น เว็บเซอร์วิสระยะไกล แต่จะให้ข้อมูลเวอร์ชันที่แคชไว้แก่ Caller ในการเรียกใช้ครั้งต่อๆ ไป เลเยอร์การดำเนินการแบบอ้อมนี้ช่วยให้คุณใช้กลยุทธ์การแคชที่มีประสิทธิภาพซึ่งเฉพาะเจาะจงกับแอปของคุณได้ ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ Repository Pattern ภายในแอปได้ที่คำแนะนำเกี่ยวกับสถาปัตยกรรมของแอป