ช่วงนี้งานค่อนข้างเยอะ เลยทำให้ปลีกตัวมาเขียนบทความไม่ค่อยได้ซักเท่าไร แต่เพื่อไม่ให้ขาดความเคลื่อนไหว เจ้าของบล็อกจึงขอเขียนเป็นบทความง่ายๆแทนไปก่อนดีกว่า
สำหรับบทความนี้จะเป็นการดึง Resource หรือไฟล์ที่อยู่ในโฟลเดอร์ res
มาใช้งาน โดยใช้ชื่อไฟล์ที่เป็น String เป็นตัวกำหนดว่าจะดึงไฟล์ไหน
การทำงานเบื้องต้นของ Resource บนแอนดรอยด์
ผู้ที่หลงเข้ามาอ่านทุกคนย่อมรู้อยู่แล้วว่าเวลาจะเรียก Resource ใดๆในโฟลเดอร์ res
จะต้องเรียกผ่าน ID ของไฟล์นั้นๆ
เมื่อนักพัฒนาเพิ่มไฟล์เข้ามาใน Resource ไฟล์นั้นๆก็จะถูกสร้าง Resource ID เฉพาะตัวขึ้นมาแล้วเก็บไว้ในไฟล์ที่ชื่อว่า R.java
เพื่อให้นักพัฒนาสามารถเรียกใช้งานในโค๊ดโดยไม่ต้องกำหนด Path ของไฟล์โดยตรง แต่จะเรียกผ่าน R.drawable.ic_launcher
แทน ซึ่งในความเป็นจริงก็คือ Integer ที่เก็บค่าตัวเลขไว้ ตัวอย่างเช่น 0x7f040019 (ค่าตัวเลขนี้ระบบ Generate ขึ้นมาให้ตอนที่ Build Project)
ที่ต้องทำแบบนี้ก็เพื่อที่ว่าตัวแอนดรอยด์จะได้จัดการกับ Resource Configuration ได้ง่ายขึ้น แยกโฟลเดอร์เป็น mdpi
, hdpi
และ xhdpi
ได้ (หรืออื่นๆ) โดยที่นักพัฒนาไม่ต้องไปพิมพ์ชื่อโฟลเดอร์ย่อยๆพวกนี้เอง ที่ต้องทำก็แค่เรียกไปที่ R.drawable.ic_launcher
เท่านั้น ที่เหลือระบบจะจัดการให้ว่าต้องไปเรียกที่โฟลเดอร์ drawable-mdpi
, drawable-hdpi
หรือว่า drawable-xhdpi
Resource ID ไม่ได้ถูกกำหนดตายตัว
เนื่องจาก ID นั้นถูก Generate จากระบบ และเมื่อมีการแก้ไขไฟล์ในนั้นไปเรื่อยๆก็จะทำให้ Resource ID ของไฟล์นั้นๆเปลี่ยนแปลงได้
นั่นก็หมายความว่านักพัฒนาไม่สามารถใช้ Resource ID เพื่ออ้างอิงไฟล์นั้นๆได้เสมอไป เพราะวันหนึ่งที่นักพัฒนาแก้ไขโปรเจคนั้นๆอาจจะทำให้ Resource ID เปลี่ยนไปได้ แล้วเกิดปัญหาข้อมูลที่เคยเก็บไว้ไม่สามารถใช้ได้ เพราะหาไฟล์นั้นๆไม่เจอ
แล้วจะใช้วิธีไหนดีล่ะ?
จริงๆมีอีกหลายวิธีที่ทำให้นักพัฒนาไม่ต้องไปเก็บค่า Resource ID โดยตรง และบทความนี้ก็เป็นหนึ่งในวิธีที่ว่า โดยจะใช้การกำหนดจากชื่อไฟล์ที่อยู่ใน Resource นั่นแหละ เพื่อใช้ในการดึงไฟล์นั้นๆมาใช้งาน
เอา String มาดึงไฟล์จาก Resource ได้ด้วยหรอ?
ได้นะเออ แต่ว่าเป็นวิธีการทางอ้อมมากกว่า เพราะเมื่อนักพัฒนารู้ว่าไฟล์ใน Resource ถูกระบุตำแหน่งด้วย Resource ID ที่เป็นชุดตัวเลข Integer ที่ระบบ Generate ขึ้นมา ดังนั้นก็ต้องเอาชื่อไฟล์ที่เป็น String นี่แหละ ไปหามาว่าไฟล์ที่ชื่อนี้มี Resource ID เป็นอะไร แล้วค่อยเอา Resource ID ที่ได้ไปดึงไฟล์อีกที
ข้อควรจำ กำหนดแค่ชื่อไฟล์ ไม่ต้องใส่นามสกุลไฟล์นะจ๊ะ
ซึ่งหัวใจหลักคือตอนที่เอาชื่อไฟล์ที่เป็น String ไปหาค่า Resource ID ส่วนตอนเอา Resource ID ไปดึง Drawable มาใช้งานไม่ใช่เรื่องยากอะไร เพราะปกติเวลาเรียกใช้ R.drawable.ic_launcher
ก็คือการใส่ Resource ID อยู่แล้ว
และการหา Resource ID ด้วย String จะใช้คำสั่งดังนี้
fun getResourceByFilename(context: Context, filename: String): Int {
return context.resources.getIdentifier(filename, "drawable", context.packageName)
}
Parameter ที่ต้องใช้มีด้วยกันสองตัวคือ Context เพื่อเข้าถึง Resource และ String ที่เป็นชื่อไฟล์ที่ต้องการหา Resource ID
val context: Context = /* ... */
val imageView: ImageView = /* ... */
val resId: Int = getResourceByFilename(context, "ic_launcher")
imageView.setImageResource(resId)
เพียงเท่านี้ก็สามารถดึง ic_launcher
มาแสดงใน ImageView ได้แล้ว~
และถ้าสังเกตดีๆจะเห็นว่าสามารถเปลี่ยน Resource ที่ต้องการได้ด้วยนะ เช่น Mipmap Resource เป็นต้น เพราะในคำสั่ง getIdentifier
มีการกำหนดชื่อ Resource อยู่ด้วย
fun getResourceByFilename(context: Context, filename: String): Int {
return context.resources.getIdentifier(filename, "mipmap", context.packageName)
}
เท่านี้ก็ดึง Resource ID จาก Mipmap Resource ได้แล้ว
ถ้าเขียนให้ครอบคลุมกว่านี้หน่อยก็จะได้ประมาณนี้
fun getResourceByFilename(context: Context, resourceType: String, filename: String): Int {
return context.resources.getIdentifier(filename, resourceType, context.packageName)
}
แล้วเวลาเรียกใช้งานก็กำหนด Resource ที่ต้องการด้วย
val context: Context = /* ... */
val resId: Int = getResourceByFilename(context, "drawable", "ic_launcher")
เพียงเท่านี้ก็เอาไปใช้งานได้หลากหลายแล้ว ไม่ว่าจะเป็น Layout Resource, String Resource หรือ Color Resource ก็ตาม