24 July 2014

ทำไมภาพถึงไม่ยอมแสดงใน Gallery

Updated on



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

        ผู้ที่หลงเข้ามาอ่านก็เป็นหนึ่งในนั้นที่ประสบปัญหาหรือว่าเคยประสบปัญหาล่ะสิ เพราะงั้นอ่านบทความนี้ต่อได้เลย~

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

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

        แล้วจะทำยังไงให้มันไวกว่าวิธีดังกล่าว?

        นั่นก็คือสแกนไฟล์เพียงแค่ครั้งแรกเท่านั้น (นั่นก็คือตอนเปิดเครื่อง) แล้วบันทึกเก็บตำแหน่งไฟล์ภาพทั้งหมดไว้ว่าอยู่ตำแหน่งใดในเครื่องบ้าง เจ้าสิ่งที่ทำหน้านี้ที่มีชื่อเรียกว่า Media Scanner นั่นเอง โดย Gallery ก็จะอิงตำแหน่งไฟล์ภาพทั้งหมดจาก Media Scanner  (เอา Path มาทำเป็นภาพ Thumbnail เพื่อแสดงผลอีกที) ดังนั้นหัวใจสำคัญจะอยู่ที่ Media Scanner



        ถ้าภาพมีการย้ายตำแหน่งล่ะ?

        ก็จะเกิดคำถามต่อว่าผู้ใช้ย้ายตำแหน่งภาพด้วยอะไรล่ะ? นั่นก็คือย้ายภาพด้วยแอปพลิเคชันนั่นเอง ซึ่งหัวใจสำคัญส่วนหนึ่งก็อยู่ที่แอปพลิเคชันนี่ล่ะ ที่จะบอกว่าภาพถูกย้ายไปที่ไหน ดังนั้นเมื่อภาพถูกย้ายด้วยแอปพลิเคชันใดๆ แอปพลิเคชันนั้นๆก็จะบอกกับ Media Scanner ด้วยว่าภาพย้ายไปไว้ที่ไหน ส่วนตำแหน่งเดิมไว้เวลาที่ Media Scanner ทำงานก็จะรู้เองว่าภาพไม่อยู่ที่ตำแหน่งนั้นแล้ว รวมไปถึงการย้ายภาพจาก MTP ด้วยเช่นกัน



        หัวใจสำคัญอยู่ที่แอปพลิเคชัน

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

        ส่วนการสั่งงานดังกล่าวจะใช้ Intent เข้ามากำหนดไฟล์ที่ต้องการอัปเดตแล้วส่งค่าด้วยคำสั่ง sendBroadcast ดังตัวอย่างข้างล่างนี้

public void updateImage(String path) {
    Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(path);
    intent.setData(Uri.fromFile(f));
    sendBroadcast(intent);
}

String filePath = ..
updateImage(filePath);

...

        จากตัวอย่างข้างบนคือฟังก์ชันที่เอาไว้อัปเดตไฟล์ให้กับ Media Scanner เพียงแค่กำหนด Path ของไฟล์ที่ต้องการอัปเดตก็ได้แล้ว ง่ายล่ะสิ!

        หรือถ้าใช้งานคลาส File อยู่แล้ว ก็ทำแบบนี้ได้เช่นกัน จะได้ไม่ต้องมาดึง String ให้เสียเวลา

public void updateImage(File file) {
    Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    intent.setData(Uri.fromFile(file));
    sendBroadcast(intent);
}

File file = ...
updateImage(file);

...

        หรือใช้งานเป็นคลาส Uri ก็ใส่ uri ตรงไปตรงๆได้เช่นกัน ไม่ต้องแปลงเป็นคลาส File ให้เสียเวลา

public void updateImage(Uri uri) {
    Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    intent.setData(uri);
    sendBroadcast(intent);
}

Uri uri = ...
updateImage(uri);

...

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