Codelab นี้เป็นส่วนหนึ่งของหลักสูตรพื้นฐานเกี่ยวกับ Kotlin ใน Android คุณจะได้รับประโยชน์สูงสุดจากหลักสูตรนี้ หากทํางานผ่าน Codelab ตามลําดับ Codelab ของหลักสูตรทั้งหมดจะแสดงอยู่ในหน้า Landing Page ของ Codelab ของ Android Kotlin Fundamentals
บทนำ
ใน Codelab นี้ปรับปรุงแอป DiceRoller จาก Codelab ล่าสุดและเรียนรู้วิธีเพิ่มและใช้ทรัพยากรรูปภาพในแอป นอกจากนี้ คุณยังเรียนรู้เกี่ยวกับความเข้ากันได้ของแอปกับ Android เวอร์ชันต่างๆ และวิธีที่ Android Jetpack ช่วยคุณได้อีกด้วย
สิ่งที่ควรทราบอยู่แล้ว
- วิธีสร้างโปรเจ็กต์แอปใหม่และเรียกใช้แอปในโปรแกรมจําลองหรืออุปกรณ์จริง
- คอมโพเนนต์พื้นฐานของโปรเจ็กต์แอป รวมถึงไดเรกทอรีทรัพยากร (
res
) และไฟล์บิลด์ของ Gradle - วิธีแก้ไขไฟล์เลย์เอาต์ของแอป
- วิธีค้นหาและแก้ไขออบเจ็กต์ข้อมูลพร็อพเพอร์ตี้ในโค้ดของแอป
สิ่งที่จะได้เรียนรู้
- วิธีเพิ่มไฟล์ไปยังทรัพยากรของแอป
- วิธีใช้รูปภาพในเลย์เอาต์ของแอป
- วิธีค้นหายอดดูอย่างมีประสิทธิภาพยิ่งขึ้นในโค้ดของแอป
- วิธีใช้รูปภาพตัวยึดตําแหน่งในการออกแบบของแอปด้วยเนมสเปซ XML
- เกี่ยวกับระดับ API ของ Android สําหรับแอปของคุณ และวิธีทําความเข้าใจระดับ API ขั้นต่ํา ที่กําหนดเป้าหมาย และที่คอมไพล์แล้ว
- วิธีใช้ไลบรารี Jetpack ในแอปเพื่อรองรับ Android เวอร์ชันเก่า
สิ่งที่จะทําได้
- แก้ไขแอป DiceRoller จาก Codelab ครั้งล่าสุดเพื่อรวมรูปภาพสําหรับค่าลูกเต๋า แทนที่จะใส่ตัวเลข
- เพิ่มไฟล์ภาพลงในทรัพยากรของแอป
- อัปเดตเลย์เอาต์และโค้ดของแอปเพื่อใช้รูปภาพสําหรับค่าไดร์ฟแทนตัวเลข
- อัปเดตโค้ดเพื่อให้ดูได้อย่างมีประสิทธิภาพยิ่งขึ้น
- อัปเดตโค้ดเพื่อใช้รูปภาพเปล่าเมื่อแอปเริ่มทํางาน
- อัปเดตแอปเพื่อใช้ไลบรารี Android Jetpack ที่เข้ากันได้กับ Android เวอร์ชันเก่า
ใน Codelab นี้ คุณสร้างในแอป DiceRoller ที่เริ่มต้นใน Codelab ก่อนหน้า และจะเพิ่มรูปภาพลูกเต๋าที่เปลี่ยนแปลงไปเมื่อมีการทอยลูกเต๋า แอป DiceRoller สุดท้ายจะมีลักษณะดังนี้
หากคุณไม่ได้ใช้ Codelab ล่าสุด คุณจะดาวน์โหลดแอปเริ่มต้นได้ที่นี่ DiceRoller
ในตอนท้ายของ Codelab ที่ผ่านมา คุณมีแอปที่อัปเดตมุมมองข้อความซึ่งมีตัวเลข 1 ถึง 6 ทุกครั้งที่ผู้ใช้แตะปุ่ม แต่แอปนี้เรียกว่า DiceRoller ไม่ใช่โปรแกรมสร้างตัวเลข 1-6 ดังนั้นลูกเต๋าจะดูเหมือนลูกเต๋าจริงๆ ในงานนี้ คุณจะต้องเพิ่มรูปภาพลูกเต๋าลงในแอป จากนั้นแทนที่จะอัปเดตข้อความเมื่อกดปุ่ม คุณจะสลับรูปภาพอื่นสําหรับผลการค้นหาม้วนแต่ละรายการได้
ขั้นตอนที่ 1: เพิ่มรูปภาพ
- เปิดโปรเจ็กต์แอป DiceRoller ใน Android Studio หากยังไม่ได้เปิด หากคุณไม่ได้ใช้ Codelab ล่าสุด คุณจะดาวน์โหลดแอปได้ที่ DiceRoller
- ในมุมมองโปรเจ็กต์ > ให้ขยายโฟลเดอร์ res และขยายวาดเขียน
แอปของคุณใช้ทรัพยากรต่างๆ มากมาย รวมถึงรูปภาพและไอคอน สี สตริง และเลย์เอาต์ XML ทรัพยากรทั้งหมดเหล่านั้นจะอยู่ในโฟลเดอร์res
โฟลเดอร์drawable
คือที่ที่คุณควรวางทรัพยากรรูปภาพทั้งหมดสําหรับแอปไว้ ในโฟลเดอร์drawable
คุณจะพบทรัพยากรสําหรับไอคอน Launcher ของแอปอยู่แล้ว - ดับเบิลคลิก ic_ Launcher_background.xml โปรดทราบว่านี่เป็นไฟล์ XML ที่อธิบายไอคอนเป็นรูปภาพเวกเตอร์ เวกเตอร์ช่วยให้สามารถวาดรูปภาพของคุณในขนาดและความละเอียดต่างๆ มากมาย อาจต้องปรับขนาดรูปภาพบิตแมป เช่น PNG หรือ GIF สําหรับอุปกรณ์ที่ต่างกัน ซึ่งอาจส่งผลให้คุณภาพลดลง
- คลิกแสดงตัวอย่างในคอลัมน์ด้านขวาของตัวแก้ไข XML เพื่อดูเวกเตอร์ที่วาดได้ในรูปแบบภาพ
- ดาวน์โหลดรูปภาพลูกเต๋าสําหรับแอปจาก DiceImages.zip แตกไฟล์ ZIP คุณควรจะมีโฟลเดอร์ของไฟล์ XML ที่มีลักษณะดังนี้
- ใน Android Studio ให้คลิกเมนูแบบเลื่อนลงที่ด้านบนของมุมมองโปรเจ็กต์ที่มีข้อความว่า Android แล้วเลือกโปรเจ็กต์ ภาพหน้าจอด้านล่างแสดงโครงสร้างของแอปในระบบไฟล์
- ขยาย DiceRoller > app > src > main > res >Drawable
- ลากไฟล์ XML ทั้งหมดจากโฟลเดอร์
DiceImages
ไปไว้ใน Android Studio และไปยังโฟลเดอร์ Drawable คลิก OK
- ให้เปลี่ยนโปรเจ็กต์กลับไปเป็นมุมมอง Android และสังเกตเห็นว่าไฟล์ XML ลูกเต๋าของคุณอยู่ในโฟลเดอร์ที่วาดได้
- ดับเบิลคลิกที่
dice_1.xml
และสังเกตโค้ด XML ของรูปภาพนี้ คลิกปุ่มแสดงตัวอย่างเพื่อดูตัวอย่างของเวกเตอร์ที่วาดได้นี้
ขั้นตอนที่ 2: อัปเดตเลย์เอาต์เพื่อใช้รูปภาพ
เมื่อมีไฟล์ภาพลูกเต๋าในโฟลเดอร์ res/drawables
แล้ว คุณจะเข้าถึงไฟล์เหล่านั้นจากเลย์เอาต์และโค้ดของแอปได้ ในขั้นตอนนี้ คุณจะแทนที่ TextView
ที่แสดงตัวเลขด้วย ImageView
เพื่อแสดงรูปภาพ
- เปิดไฟล์รูปแบบ
activity_main.xml
หากยังไม่ได้เปิด คลิกแท็บข้อความเพื่อดูโค้ด XML ของเลย์เอาต์ - ลบองค์ประกอบ
<TextView>
- เพิ่มเอลิเมนต์
<ImageView>
ที่มีแอตทริบิวต์เหล่านี้
<ImageView
android:id="@+id/dice_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/dice_1" />
ใช้ ImageView
เพื่อแสดงรูปภาพในเลย์เอาต์ แอตทริบิวต์ใหม่เพียงรายการเดียวขององค์ประกอบนี้คือ android:src
เพื่อระบุทรัพยากรแหล่งที่มาของรูปภาพ ในกรณีนี้ แหล่งที่มาของรูปภาพ @drawable/dice_1
หมายความว่า Android ควรดูทรัพยากรที่ดึงมาได้ (res/drawable
) ของรูปภาพที่มีชื่อว่า dice_1
- คลิกปุ่มแสดงตัวอย่างเพื่อดูตัวอย่างเลย์เอาต์ ซึ่งควรมีลักษณะดังนี้
ขั้นตอนที่ 3: อัปเดตโค้ด
- เปิด
MainActivity
ฟังก์ชันrollDice()
มีลักษณะดังนี้
private fun rollDice() {
val randomInt = Random().nextInt(6) + 1
val resultText: TextView = findViewById(R.id.result_text)
resultText.text = randomInt.toString()
}
โปรดสังเกตว่าการอ้างอิงไปยัง R.id.result_text
อาจมีการไฮไลต์เป็นสีแดง นั่นคือเพราะคุณลบ TextView
จากเลย์เอาต์ และรหัสนั้นไม่มีอยู่แล้ว
- ลบเส้น 2 เส้นที่ส่วนท้ายของฟังก์ชันที่กําหนดตัวแปร
resultText
และตั้งค่าคุณสมบัติของข้อความ คุณไม่ได้ใช้TextView
ในเลย์เอาต์แล้ว ดังนั้นจึงไม่จําเป็นต้องต่ออีก 2-3 บรรทัด - ใช้
findViewByID()
เพื่อรับการอ้างอิงImageView
ใหม่ในเลย์เอาต์ตามรหัส (R.id.dice_image
) และกําหนดมุมมองดังกล่าวให้กับตัวแปรdiceImage
ใหม่
val diceImage: ImageView = findViewById(R.id.dice_image)
- เพิ่มบล็อก
when
เพื่อเลือกรูปภาพลูกเต๋าที่เจาะจงตามค่าของrandomInteger
:
val drawableResource = when (randomInt) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
else -> R.drawable.dice_6
}
เช่นเดียวกับรหัส คุณสามารถอ้างอิงรูปภาพลูกเต๋าในโฟลเดอร์ที่วาดได้ด้วยค่าในชั้นเรียน R
ในที่นี้ R.drawable
จะหมายถึงโฟลเดอร์ที่วาดได้ของแอป และ dice_1
เป็นทรัพยากรรูปภาพไดฟ์ที่เฉพาะเจาะจงภายในโฟลเดอร์นั้น
- อัปเดตแหล่งที่มาของ
ImageView
ด้วยเมธอดsetImageResource()
และการอ้างอิงไปยังรูปภาพไดร์ฟที่คุณเพิ่งพบ
diceImage.setImageResource(drawableResource)
- คอมไพล์และเรียกใช้แอป เมื่อคลิกปุ่มม้วนรูปภาพ รูปภาพควรอัปเดตเป็นรูปภาพที่เหมาะสม
ทุกอย่างในแอปของคุณทํางานได้ แต่ยังมีมากกว่าแค่การพัฒนาแอปไม่ใช่แค่การมีโค้ดที่ใช้งานได้ รวมถึงเข้าใจวิธีเขียนแอปที่มีประสิทธิภาพและมีประสิทธิภาพสูงด้วย ซึ่งหมายความว่าแอปควรทํางานได้ดี แม้ว่าผู้ใช้จะไม่มีอุปกรณ์ Android ที่แพงที่สุดหรือการเชื่อมต่อเครือข่ายที่ดีที่สุด นอกจากนี้แอปควรทํางานได้อย่างราบรื่นในขณะที่เพิ่มฟีเจอร์เพิ่มเติม และโค้ดควรอ่านได้ง่ายและเป็นระเบียบ
ในงานนี้ คุณจะได้เรียนรู้เกี่ยวกับวิธีหนึ่งในการทําให้แอปมีประสิทธิภาพมากขึ้น
- เปิด
MainActivity
หากยังไม่ได้เปิด ในเมธอดrollDice()
โปรดสังเกตการประกาศสําหรับตัวแปรdiceImage
ดังนี้
val diceImage : ImageView = findViewById(R.id.dice_image)
เนื่องจาก rollDice()
เป็นเครื่องจัดการคลิกสําหรับปุ่มม้วน ทุกครั้งที่ผู้ใช้แตะปุ่มดังกล่าว แอปของคุณจะเรียกใช้ findViewById()
และจะได้รับการอ้างอิงอีกครั้งไปยัง ImageView
นี้ โดยหลักการแล้ว คุณควรลดจํานวนการเรียกไปยัง findViewById()
เนื่องจากระบบ Android ค้นหาลําดับชั้นของการดูทั้งหมดในแต่ละครั้ง ซึ่งนับเป็นการดําเนินการที่แพง
ในแอปขนาดเล็กอย่างข้อความนี้ นี่ไม่ใช่ปัญหาใหญ่ หากคุณใช้แอปที่ซับซ้อนมากขึ้นในโทรศัพท์ที่ช้า การเรียกใช้ findViewById()
อย่างต่อเนื่องอาจทําให้แอปล่าช้า แนวทางปฏิบัติแนะนําคือการเรียก findViewById()
เพียงครั้งเดียวและจัดเก็บออบเจ็กต์ View
ในช่องแทน การเก็บการอ้างอิง ImageView
ไว้ในช่องจะช่วยให้ระบบเข้าถึง View
ได้โดยตรงได้ทุกเมื่อ ซึ่งช่วยปรับปรุงประสิทธิภาพการทํางาน
- ที่ด้านบนสุดของช่อง ก่อน
onCreate()
ให้สร้างช่องเพื่อใช้เก็บImageView
var diceImage : ImageView? = null
โดยหลักการแล้ว ควรเริ่มต้นตัวแปรนี้ที่นี่เมื่อประกาศหรือในตัวสร้าง แต่กิจกรรม Android จะไม่ใช้เครื่องมือสร้าง ความจริงแล้ว มุมมองในเลย์เอาต์นั้นไม่สามารถเข้าถึงวัตถุในหน่วยความจําได้เลยจนกว่าจะเป่าเมธอด onCreate()
ตามการเรียก setContentView()
คุณจะเริ่มตัวแปร diceImage
ไม่ได้จนกว่าเหตุการณ์จะเสร็จสิ้น
อีกทางเลือกหนึ่งคือการกําหนดให้ตัวแปร diceImage
เป็น Null ในตัวอย่างนี้ ตั้งค่าเป็น null
เมื่อประกาศแล้ว จากนั้นจึงมอบหมายให้ ImageView
จริงใน onCreate()
ด้วย findViewById()
อย่างไรก็ตาม โค้ดนี้อาจทําให้โค้ดของคุณซับซ้อน เนื่องจากคุณต้องตรวจสอบค่า null
ทุกครั้งที่คุณต้องการใช้ diceImage
เราเชื่อว่าต้องมีหนทางที่ดีกว่า
- เปลี่ยนการประกาศ
diceImage
เพื่อใช้คีย์เวิร์ดlateinit
และนําการมอบหมายnull
ออก
lateinit var diceImage : ImageView
คีย์เวิร์ด lateinit
สัญญาให้คอมไพเลอร์ Kotlin ทราบว่าจะเริ่มต้นตัวแปรก่อนโค้ดจะเรียกดําเนินการใดๆ กับตัวแปร เราจึงไม่จําเป็นต้องเริ่มต้นตัวแปรเป็น null
ที่นี่ และเราจะถือว่าตัวแปรเป็นตัวแปรที่ไม่สามารถยกเลิกได้เมื่อเราใช้ แนวทางปฏิบัติแนะนําคือใช้ lateinit
กับช่องที่มีมุมมองในลักษณะนี้
- ใน
onCreate()
หลังจากวิธีการsetContentView()
ให้ใช้findViewById()
เพื่อรับImageView
diceImage = findViewById(R.id.dice_image)
- ลบบรรทัดเก่าใน
rollDice()
ที่ประกาศและรับImageView
คุณได้แทนที่บรรทัดนี้ด้วยการประกาศของช่องก่อนหน้านี้
val diceImage : ImageView = findViewById(R.id.dice_image)
- เรียกใช้แอปอีกครั้งเพื่อดูว่าแอปยังคงทํางานตามที่คาดไว้
ขณะนี้คุณกําลังใช้ dice_1
เป็นรูปภาพเริ่มต้นสําหรับลูกเต๋า สมมติว่าคุณไม่ต้องการแสดงรูปภาพใดๆ จนกว่าจะทอยลูกเต๋าเป็นครั้งแรก การดําเนินการดังกล่าวทําได้หลายวิธี
- เปิด
activity_layout.xml
ในแท็บข้อความ - ในองค์ประกอบ
<ImageView>
ให้ตั้งค่าแอตทริบิวต์android:src
เป็น"@drawable/empty_dice"
:
android:src="@drawable/empty_dice"
รูปภาพ empty_dice
เป็นหนึ่งในรูปภาพที่คุณดาวน์โหลดและเพิ่มลงในโฟลเดอร์ drawable
ขนาดดังกล่าวมีขนาดเท่ากับรูปภาพลูกเต๋าอื่นๆ แต่ขนาดจะว่างเปล่า รูปภาพนี้เป็นรูปภาพที่จะแสดงขึ้นเมื่อแอปเริ่มทํางานเป็นครั้งแรก
- คลิกแท็บการออกแบบ รูปภาพหุ่นตายว่างเปล่าแล้ว แต่รูปภาพนี้จะไม่ปรากฏในตัวอย่างด้วย
ค่อนข้างเป็นเรื่องปกติที่เนื้อหาการออกแบบอาจได้รับการกําหนดแบบไดนามิกในช่วงรันไทม์ เช่น แอปที่ดึงข้อมูลจากอินเทอร์เน็ตควรเริ่มต้นด้วยหน้าจอว่างหรือว่างเปล่า แต่จะมีประโยชน์เมื่อคุณออกแบบแอปให้แสดงข้อมูลตัวยึดตําแหน่งบางส่วนในเลย์เอาต์เพื่อให้คุณทราบข้อมูลที่กําลังวางอยู่ - ใน
activity_layout.xml
ให้คัดลอกบรรทัดandroid:src
และวางสําเนาที่ 2 เปลี่ยนคํา "android" เป็น "tools" เพื่อให้แอตทริบิวต์ทั้ง 2 ของคุณมีลักษณะดังนี้
android:src="@drawable/empty_dice"
tools:src="@drawable/empty_dice" />
นี่ คุณได้เปลี่ยนแปลงเนมสเปซ XML ของแอตทริบิวต์นี้จากเนมสเปซ android
ที่เป็นค่าเริ่มต้นเป็นเนมสเปซ tools
เนมสเปซ tools
จะใช้ได้เมื่อคุณต้องการกําหนดเนื้อหาตัวยึดตําแหน่งที่ใช้เฉพาะในการแสดงตัวอย่างหรือตัวแก้ไขดีไซน์ใน Android Studio ระบบจะนําแอตทริบิวต์ที่ใช้เนมสเปซ tools
ออกเมื่อคุณคอมไพล์แอป
เนมสเปซใช้ในการช่วยแก้ปัญหาความกํากวมเมื่อพูดถึงแอตทริบิวต์ที่มีชื่อเดียวกัน ตัวอย่างเช่น แอตทริบิวต์ทั้งสองในแท็ก <ImageView>
มีชื่อเดียวกัน (src
) แต่เนมสเปซต่างกัน
- ตรวจสอบองค์ประกอบ
<LinearLayout>
ที่รากของไฟล์เลย์เอาต์และสังเกตเนมสเปซทั้ง 2 รายการที่กําหนดไว้ที่นี่
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
...
- เปลี่ยนแอตทริบิวต์
tools:src
ในแท็กImageView
เป็นdice_1
แทนempty_dice
ดังนี้
android:src="@drawable/empty_dice"
tools:src="@drawable/dice_1" />
โปรดสังเกตว่ามีรูปภาพ dice_1
วางเป็นรูปภาพตัวยึดตําแหน่งในหน้าตัวอย่างแล้ว
- คอมไพล์และเรียกใช้แอป โปรดสังเกตว่ารูปภาพไดร์ฟว่างเปล่าในแอปจริงจนกว่าคุณจะคลิกหรือแตะกลิ้ง
ข้อดีอย่างหนึ่งของการพัฒนาแอป Android คือจํานวนโค้ดที่โค้ดใช้ได้
เมื่อเขียนสําหรับ Android คุณจะเขียนแอปแยกต่างหากสําหรับอุปกรณ์แต่ละเครื่องแยกกันไม่ได้ แม้กระทั่งแอปที่ทํางานโดยใช้รูปแบบที่แตกต่างกันอย่างสิ้นเชิง เช่น นาฬิกาและทีวี ก็จะแชร์รหัสได้ แต่ก็ยังมีข้อจํากัดและกลยุทธ์ความเข้ากันได้ที่คุณควรทราบเพื่อสนับสนุนการดําเนินการทั้งหมด
ในงานนี้ คุณจะได้ดูวิธีกําหนดเป้าหมายแอปสําหรับ Android API เวอร์ชันต่างๆ (เวอร์ชัน) และวิธีใช้ไลบรารี Android Jetpack เพื่อรองรับอุปกรณ์รุ่นเก่า
ขั้นตอนที่ 1: สํารวจระดับ API
ใน Codelab ก่อนหน้า เมื่อสร้างโปรเจ็กต์ คุณได้ระบุระดับ Android API ที่เจาะจงซึ่งแอปควรรองรับ ระบบปฏิบัติการ Android มีหมายเลขเวอร์ชันต่างกันซึ่งตั้งชื่อตามความสวยงามซึ่งเรียงตามลําดับตัวอักษร ระบบปฏิบัติการแต่ละเวอร์ชันจะจัดส่งด้วยฟังก์ชันและฟังก์ชันใหม่ๆ ตัวอย่างเช่น Android Oreo ส่งการรองรับแอปการแสดงภาพซ้อนภาพ ส่วน Android Pie ขอแนะนํา Slices ระดับ API จะสอดคล้องกับเวอร์ชัน Android เช่น API 19 สอดคล้องกับ Android 4.4 (KitKat)
เนื่องด้วยปัจจัยหลายประการ รวมถึงสิ่งที่ฮาร์ดแวร์รองรับได้ ผู้ใช้เลือกที่จะอัปเดตอุปกรณ์ของตนหรือไม่ และผู้ผลิตรองรับระบบปฏิบัติการระดับต่างๆ หรือไม่ ท้ายที่สุดแล้วผู้ใช้ก็ใช้งานอุปกรณ์เวอร์ชันระบบปฏิบัติการที่แตกต่างกัน
เมื่อสร้างโปรเจ็กต์แอป คุณต้องระบุระดับ API ขั้นต่ําที่แอปรองรับ กล่าวคือคุณระบุ Android เวอร์ชันเก่าที่สุดที่แอปรองรับ แอปยังมีระดับที่จะคอมไพล์ และระดับที่จะกําหนดเป้าหมายด้วย ในแต่ละระดับจะเป็นพารามิเตอร์การกําหนดค่าในไฟล์บิลด์ Gradle
- ขยายโฟลเดอร์ Gradle Scripts และเปิดไฟล์ build.gradle (โมดูล: แอป)
ไฟล์นี้จะกําหนดพารามิเตอร์บิวด์และทรัพยากร Dependency สําหรับโมดูลแอปโดยเฉพาะ ไฟล์ build.gradle (โครงการ: DiceRoller) จะกําหนดพารามิเตอร์บิวด์สําหรับโครงการโดยรวม ในหลายๆ กรณี โมดูลแอปจะเป็นโมดูลเดียวในโปรเจ็กต์ของคุณ ดังนั้นการแบ่งแผนกนี้อาจมีลักษณะที่กําหนดเอง แต่หากแอปของคุณซับซ้อนขึ้นและแบ่งออกเป็นหลายส่วน หรือหากแอปรองรับแพลตฟอร์มอย่างเช่น นาฬิกา Android คุณอาจเห็นโมดูลต่างๆ ในโปรเจ็กต์เดียวกัน - ตรวจสอบส่วน
android
ที่ด้านบนสุดของไฟล์build.gradle
(ตัวอย่างด้านล่างไม่ใช่ทั้งส่วน แต่ประกอบด้วยสิ่งที่คุณสนใจมากที่สุดสําหรับ Codelab นี้)
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.android.diceroller"
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
- ตรวจสอบพารามิเตอร์
compileSdkVersion
compileSdkVersion 28
พารามิเตอร์นี้ระบุระดับ API ของ Android ที่ Gradle ควรใช้เพื่อรวบรวมแอปของคุณ นี่เป็น Android เวอร์ชันล่าสุดที่แอปของคุณรองรับได้ ซึ่งหมายความว่าแอปของคุณอาจใช้ฟีเจอร์ API ที่รวมอยู่ในระดับ API นี้และต่ํากว่าได้ ในกรณีนี้ แอปของคุณรองรับ API 28 ซึ่งสอดคล้องกับ Android 9 (Pie)
- ตรวจสอบพารามิเตอร์
targetSdkVersion
ซึ่งอยู่ในส่วนdefaultConfig
targetSdkVersion 28
ค่านี้จะเป็น API ล่าสุดที่คุณใช้ทดสอบแอป ซึ่งในหลายๆ กรณี ค่านี้จะเป็นค่าเดียวกับ compileSdkVersion
- ตรวจสอบพารามิเตอร์
minSdkVersion
minSdkVersion 19
พารามิเตอร์นี้มีความสําคัญมากที่สุดจากทั้ง 3 แบบ เนื่องจากจะกําหนด Android เวอร์ชันเก่าที่สุดที่แอปของคุณจะทํางาน อุปกรณ์ที่ใช้ระบบปฏิบัติการ Android เก่ากว่าระดับ API นี้จะเรียกใช้แอปไม่ได้เลย
การเลือกระดับ API ขั้นต่ําสําหรับแอปอาจทําได้ยาก ตั้งระดับ API ต่ําเกินไปแล้วคุณจะพลาดฟีเจอร์ใหม่ๆ ของระบบปฏิบัติการ Android ตั้งให้สูงเกินไปและแอปของคุณอาจทํางานบนอุปกรณ์รุ่นใหม่ๆ เท่านั้น
เมื่อคุณตั้งค่าโปรเจ็กต์และขึ้นมาไปยังตําแหน่งที่คุณกําหนดระดับ API ขั้นต่ําสําหรับแอป ให้คลิกช่วยฉันเลือกเพื่อดูกล่องโต้ตอบการเผยแพร่เวอร์ชัน API กล่องโต้ตอบจะให้ข้อมูลเกี่ยวกับจํานวนอุปกรณ์ที่ใช้ระดับระบบปฏิบัติการที่แตกต่างกันและฟีเจอร์ที่มีการเปลี่ยนแปลงหรือเปลี่ยนแปลงในระดับระบบปฏิบัติการ นอกจากนี้ คุณยังดูบันทึกประจํารุ่นของเอกสารประกอบและหน้าแดชบอร์ดของ Android ซึ่งมีข้อมูลเพิ่มเติมเกี่ยวกับผลกระทบของการรองรับระดับ API ต่างๆ ได้อีกด้วย
ขั้นตอนที่ 2: สํารวจความเข้ากันได้
การเขียนแอปสําหรับ Android API ระดับต่างๆ เป็นความท้าทายที่นักพัฒนาแอปพบบ่อย ทีมเฟรมเวิร์กของ Android จึงได้ทํางานอย่างหนักเพื่อช่วยเหลือคุณ
ในปี 2011 ทีมได้ปล่อยไลบรารีการสนับสนุนแห่งแรก ซึ่งเป็นไลบรารีที่พัฒนาโดย Google ซึ่งนําเสนอชั้นเรียนที่ใช้งานร่วมกันได้แบบย้อนหลังและฟังก์ชันที่มีประโยชน์ ในปี 2018 Google ได้เปิดตัว Android Jetpack ซึ่งเป็นคอลเล็กชันที่ประกอบด้วยไลบรารีและฟังก์ชันต่างๆ ก่อนหน้าของไลบรารีการสนับสนุน ขณะเดียวกันก็ขยายในคลังการสนับสนุนด้วย
- เปิด
MainActivity
- โปรดทราบว่าชั้นเรียน
MainActivity
ไม่ได้ขยายจากActivity
เอง แต่มาจากAppCompatActivity
class MainActivity : AppCompatActivity() {
...
AppCompatActivity
เป็นคลาสความเข้ากันได้เพื่อให้กิจกรรมมีลักษณะเหมือนกันทั่วทั้งแพลตฟอร์มระบบปฏิบัติการต่างๆ
- คลิกสัญลักษณ์ + ข้างบรรทัดที่ขึ้นต้นด้วย
import
เพื่อขยายการนําเข้าสําหรับชั้นเรียนของคุณ โปรดทราบว่าระบบจะนําเข้าคลาสAppCompatActivity
จากแพ็กเกจandroidx.appcompat.app
เนมสเปซสําหรับไลบรารี Android Jetpack คือandroidx
- เปิด build.gradle (โมดูล: แอป) แล้วเลื่อนลงไปยังส่วนการขึ้นต่อกัน
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.0-beta01'
implementation 'androidx.core:core-ktx:1.0.1'
implementation 'androidx.constraintlayout:constraintlayout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
androidTestImplementation
'androidx.test.espresso:espresso-core:3.1.0-alpha4'
}
แสดงทรัพยากร Dependency ในไลบรารี appcompat
ซึ่งเป็นส่วนหนึ่งของ androidx
และมีคลาส AppCompatActivity
ขั้นตอนที่ 3: เพิ่มความเข้ากันได้สําหรับภาพวาดที่เวกเตอร์ได้
คุณกําลังจะใช้ความรู้ใหม่เกี่ยวกับเนมสเปซ Gradle และความเข้ากันได้เพื่อทําการปรับเปลี่ยนสุดท้ายในแอป ซึ่งจะช่วยเพิ่มประสิทธิภาพขนาดแอปในแพลตฟอร์มเก่า
- ขยายโฟลเดอร์ res แล้วขยาย Drawable ดับเบิลคลิกรูปภาพลูกเต๋า 1 ภาพ
จากตัวอย่างก่อนหน้านี้ รูปภาพลูกเต๋าทั้งหมดเป็นไฟล์ XML ที่ระบุสีและรูปร่างของลูกเต๋า ไฟล์ประเภทนี้เรียกว่า Drawable Drawable ข้อดีของรูปแบบเวกเตอร์ที่ถอนออกได้กับรูปแบบบิตแมป เช่น PNG คือค่าที่วาดได้เวกเตอร์สามารถปรับขนาดได้โดยไม่สูญเสียคุณภาพ นอกจากนี้ เวกเตอร์ที่วาดได้ก็มักจะเป็นไฟล์ที่เล็กกว่ารูปภาพเดียวกันในรูปแบบบิตแมปมาก
สิ่งสําคัญที่ควรทราบเกี่ยวกับวาดเขียนที่เวกเตอร์ได้คือรองรับใน API 21 แต่ SDK ขั้นต่ําของแอปได้รับการตั้งค่าเป็น API 19 หากคุณเคยลองใช้แอปในอุปกรณ์หรือโปรแกรมจําลอง API 19 แล้ว คุณก็พบว่าแอปสร้างและเริ่มทํางานได้เลย วิธีนี้ทํางานอย่างไร
เมื่อคุณสร้างแอป กระบวนการสร้าง Gradle จะสร้างไฟล์ PNG จากไฟล์เวกเตอร์แต่ละไฟล์ และมีการใช้งานไฟล์ PNG เหล่านั้นในอุปกรณ์ Android รุ่นที่ต่ํากว่า 21 ไฟล์ PNG เพิ่มเติมเหล่านี้จะเพิ่มขนาดของแอป แอปขนาดใหญ่โดยไม่จําเป็นนั้นไม่ดีนัก เนื่องจากทําให้การดาวน์โหลดช้าลงสําหรับผู้ใช้และกินพื้นที่ของอุปกรณ์มากขึ้น' พื้นที่จํากัด แอปขนาดใหญ่ยังมีโอกาสที่จะถอนการติดตั้งสูงกว่า และผู้ใช้ดาวน์โหลดหรือดาวน์โหลดแอปเหล่านั้นไม่สําเร็จ
ข่าวดีคือมีไลบรารีความเข้ากันได้ของ Android X สําหรับภาพวาดที่เวกเตอร์ได้จนถึง API ระดับ 7 - เปิด build.gradle (โมดูล: แอป) เพิ่มบรรทัดนี้ลงในส่วน
defaultConfig
:
vectorDrawables.useSupportLibrary = true
- คลิกปุ่มซิงค์เลย ทุกครั้งที่มีการแก้ไขไฟล์
build.gradle
คุณจะต้องซิงค์ไฟล์บิลด์กับโปรเจ็กต์ - เปิดไฟล์รูปแบบ
main_activity.xml
เพิ่มเนมสเปซนี้ในแท็ก<LinearLayout>
ราก ใต้เนมสเปซtools
:
xmlns:app="http://schemas.android.com/apk/res-auto"
เนมสเปซ app
มีไว้สําหรับแอตทริบิวต์ที่มาจากโค้ดที่กําหนดเองหรือจากไลบรารี ไม่ใช่เฟรมเวิร์กหลักของ Android
- เปลี่ยนแอตทริบิวต์
android:src
ในองค์ประกอบ<ImageView>
เป็นapp:srcCompat
app:srcCompat="@drawable/empty_dice"
แอตทริบิวต์ app:srcCompat
ใช้ไลบรารี Android X เพื่อรองรับเวกเตอร์ที่ถอนออกได้ใน Android เวอร์ชันเก่า กลับไปที่ API ระดับ 7
- สร้างและเรียกใช้แอป คุณจะไม่เห็นสิ่งที่ต่างไปจากเดิมบนหน้าจอ แต่ตอนนี้แอปไม่ต้องใช้ #PNG ที่สร้างขึ้นสําหรับลูกเต๋าไม่ว่าจะวิ่งไปที่ใดก็ตาม ซึ่งหมายความว่าไฟล์แอปขนาดเล็กกว่า
โปรเจ็กต์ Android Studio: DiceRollerFinal
ความท้าทาย: แก้ไขแอป DiceRoller ให้มีลูกเต๋า 2 ลูก เมื่อผู้ใช้แตะปุ่มม้วน แต่ละไดร์ฟควรมีค่าเป็นอิสระต่อกัน
เคล็ดลับ: สร้างฟังก์ชันส่วนตัวใหม่เพื่อรับรูปภาพที่สุ่มได้และแสดงผลจํานวนเต็มสําหรับทรัพยากรที่ดึงได้ ใช้ฟังก์ชันนั้นสําหรับรูปภาพแต่ละรูป
private fun getRandomDiceImage() : Int { ... }
โค้ดโซลูชันสําหรับการท้าโค้ด
โปรเจ็กต์ Android Studio: DiceRollerFinal-challenge
แหล่งข้อมูลของแอป:
- ทรัพยากรของแอปอาจรวมถึงรูปภาพและไอคอน สีมาตรฐานที่ใช้ในแอป สตริง และเลย์เอาต์ XML ระบบจะเก็บทรัพยากรทั้งหมดไว้ในโฟลเดอร์
res
- โฟลเดอร์ทรัพยากร
drawable
คือที่ให้คุณวางทรัพยากรรูปภาพทั้งหมดสําหรับแอป
การใช้เวกเตอร์ที่ถอนออกได้ในมุมมองรูปภาพ
- เวกเตอร์ที่ถอนออกได้คือรูปภาพที่อธิบายในรูปแบบ XML เวกเตอร์ที่ถอนออกได้มีความยืดหยุ่นกว่าภาพบิตแมป (เช่น ไฟล์ PNG) เนื่องจากสามารถปรับขนาดเป็นขนาดหรือความละเอียดใดก็ได้
- หากต้องการเพิ่มภาพวาดที่วาดได้ลงในเลย์เอาต์ของแอป ให้ใช้องค์ประกอบ
<ImageView>
แหล่งที่มาของรูปภาพอยู่ในแอตทริบิวต์android:src
หากต้องการอ้างอิงโฟลเดอร์ทรัพยากรที่ถอนออกได้ ให้ใช้@drawable
เช่น"@drawable/image_name"
- ใช้มุมมอง
ImageView
ในโค้ดMainActivity
สําหรับรูปภาพ คุณใช้setImageResource()
เพื่อเปลี่ยนรูปภาพมุมมองเป็นทรัพยากรอื่นได้ ใช้R.drawable
เพื่ออ้างถึงทรัพยากรที่ถอนออกได้ เช่นsetImageResource(R.drawable.image_name)
คีย์เวิร์ด lateinit
คํานี้
- ย่อการเรียก
findViewById()
ในโค้ดโดยประกาศช่องเพื่อคงการดูเหล่านั้นไว้และเริ่มต้นช่องในonCreate()
ใช้คีย์เวิร์ดlateinit
กับช่องนี้เพื่อหลีกเลี่ยงไม่ให้ต้องประกาศเป็นค่าว่าง
เนมสเปซ tools
สําหรับแอตทริบิวต์เวลาออกแบบ:
- ใช้แอตทริบิวต์
tools:src
ในองค์ประกอบ<ImageView>
ในเลย์เอาต์เพื่อแสดงรูปภาพเฉพาะในตัวอย่างหรือตัวแก้ไขดีไซน์ของ Android Studio' จากนั้นคุณจะใช้รูปภาพที่ว่างเปล่าของandroid:src
สําหรับแอปสุดท้ายได้ - ใช้เนมสเปซ
tools
ในไฟล์เลย์เอาต์ของ Android เพื่อสร้างเนื้อหาตัวยึดตําแหน่งหรือคําแนะนําสําหรับเลย์เอาต์ใน Android Studio ระบบจะไม่ใช้ข้อมูลที่ประกาศโดยแอตทริบิวต์tools
ในแอปสุดท้าย
ระดับ API
- ระบบปฏิบัติการ Android แต่ละระบบจะมีหมายเลขเวอร์ชันและชื่ออย่างเป็นทางการ (เช่น Android 9.0, "Pie") และระดับ API (API 28) ใช้ระดับ API ในไฟล์ Gradle ของแอปเพื่อระบุเวอร์ชันของ Android ที่แอปของคุณรองรับ
- พารามิเตอร์
compileSdkVersion
ในไฟล์build.gradle
จะระบุระดับ Android API ที่ Gradle ควรใช้เพื่อรวบรวมแอปของคุณ - พารามิเตอร์
targetSdkVersion
จะระบุระดับ API ล่าสุดที่คุณทําการทดสอบกับแอป ในหลายกรณี พารามิเตอร์นี้จะมีค่าเหมือนกับcompileSdkVersion
- พารามิเตอร์
minSdkVersion
จะระบุระดับ API ที่เก่าที่สุดที่แอปสามารถทําได้
Android Jetpack:
- Android Jetpack คือคอลเล็กชันของไลบรารีที่พัฒนาโดย Google ซึ่งนําเสนอคลาสที่เข้ากันได้กับ Google และฟังก์ชันที่มีประโยชน์สําหรับการรองรับ Android เวอร์ชันเก่า Jetpack จะมาแทนที่และขยายชุดไลบรารีที่เคยใช้ชื่อว่า Android Support Library
- คลาสที่นําเข้าจากแพ็กเกจ
androidx
หมายถึงไลบรารี Jetpack การขึ้นต่อกันของ Jetpack ในไฟล์build.gradle
จะเริ่มต้นด้วยandroidx
ความเข้ากันได้แบบย้อนหลังสําหรับภาพวาดที่เวกเตอร์ได้
- เวอร์ชันวาดเขียนที่วาดได้จะใช้ได้เฉพาะใน Android เวอร์ชันสูงกว่า API 21 เท่านั้น ในเวอร์ชันเก่า Gradle จะสร้างรูปภาพ PNG สําหรับสิ่งที่วาดได้เหล่านั้นเมื่อสร้างแอป
- คุณระบุได้ว่าควรใช้ไลบรารีการสนับสนุนของ Android สําหรับทรัพยากรที่ถอนออกได้ใน API เวอร์ชันเก่าด้วยพารามิเตอร์การกําหนดค่า
vectorDrawables.useSupportLibrary = true
ในไฟล์build.gradle
- เมื่อคุณเปิดใช้ไลบรารีการสนับสนุนสําหรับภาพวาดที่เวกเตอร์ได้ ให้ใช้แอตทริบิวต์
app:srcCompat
ในองค์ประกอบ<ImageView>
(แทนandroid:src
) เพื่อระบุแหล่งข้อมูลที่วาดเวกเตอร์สําหรับรูปภาพนั้นได้
เนมสเปซ app
:
- เนมสเปซ
app
ในไฟล์เลย์เอาต์ XML มีไว้สําหรับแอตทริบิวต์ที่มาจากโค้ดที่กําหนดเองหรือจากไลบรารี ไม่ใช่จากเฟรมเวิร์กของ Android หลัก
หลักสูตร Udacity:
เอกสารประกอบสําหรับนักพัฒนาซอฟต์แวร์ Android
ImageView
- ภาพรวมของทรัพยากรแอป
findViewById
()
- ข้อมูลอ้างอิงเกี่ยวกับแอตทริบิวต์ของเครื่องมือ
- รองรับแพลตฟอร์มเวอร์ชันต่างๆ
- ระบุข้อกําหนดระดับ API
- Android Jetpack
อื่นๆ:
ส่วนนี้จะอธิบายการบ้านและรายงานสําหรับนักเรียนที่ทํางานผ่าน Codelab นี้ซึ่งเป็นส่วนหนึ่งของหลักสูตรที่นําโดยผู้สอน สิ่งที่ผู้สอนต้องทํามีดังนี้
- มอบหมายการบ้านหากจําเป็น
- สื่อสารกับนักเรียนเกี่ยวกับวิธีส่งงานทําการบ้าน
- ตัดเกรดการบ้าน
ผู้สอนจะใช้คําแนะนําเหล่านี้เท่าใดก็ได้หรือตามที่ต้องการก็ได้ และสามารถกําหนดให้การบ้านอื่นๆ ที่ตนคิดว่าเหมาะสมได้
หากคุณใช้ Codelab ด้วยตัวเอง ก็ให้ใช้การบ้านเพื่อทดสอบความรู้ของคุณได้
เปลี่ยนแอป
เพิ่มปุ่มล้างในแอป DiceRoller ซึ่งตั้งค่ารูปภาพเทคนิคกลับไปเป็นรูปภาพว่างเปล่า
ตอบคําถามเหล่านี้
คำถามที่ 1
แอตทริบิวต์ <ImageView>
ใดระบุรูปภาพต้นฉบับที่ควรใช้เฉพาะใน Android Studio
android:srcCompat
app:src
tools:src
tools:sourceImage
คำถามที่ 2
วิธีใดจะเปลี่ยนทรัพยากรรูปภาพของ ImageView
ในโค้ด Kotlin xmx
setImageResource()
setImageURI()
setImage()
setImageRes()
คำถามที่ 3
คีย์เวิร์ด lateinit
ในการประกาศตัวแปรระบุอะไรในโค้ดของ Kotlin
- ห้ามเริ่มต้นตัวแปร
- ตัวแปรเริ่มต้นเมื่อรันไทม์แอปเท่านั้น
- ตัวแปรเริ่มต้นเป็น
null
โดยอัตโนมัติ - ระบบจะเริ่มต้นตัวแปรในภายหลัง สาบาน
คำถามที่ 4
การกําหนดค่า Gradle ใดบ่งบอกถึงระดับ API ล่าสุดที่แอปของคุณได้รับการทดสอบ
minSdkVersion
compileSdkVersion
targetSdkVersion
testSdkVersion
คำถามที่ 5
คุณจะเห็นบรรทัดการนําเข้าในโค้ดที่ขึ้นต้นด้วย androidx
นี่หมายความว่าอย่างไร
- ชั้นเรียนนี้เป็นส่วนหนึ่งของไลบรารี Android Jetpack
- ชั้นเรียนจะอยู่ในไลบรารีภายนอกที่จะโหลดแบบไดนามิกเมื่อแอปทํางาน
- &classt;extra" เป็นตัวเลือกที่ไม่บังคับสําหรับชั้นเรียนของคุณ
- ชั้นเรียนนี้เป็นส่วนหนึ่งของการรองรับ XML ของ Android
ส่งแอปเพื่อตัดเกรด
ตรวจสอบว่าแอปมีคุณสมบัติต่อไปนี้
- เลย์เอาต์ของแอปควรมีมุมมองรูปภาพ 1 ปุ่มและปุ่ม 2 ปุ่ม
- โค้ดของแอปควรตั้งค่าเครื่องจัดการการคลิก 2 รายการ โดย 1 รายการสําหรับปุ่มแต่ละปุ่ม
- เครื่องจัดการคลิกสําหรับปุ่มล้างควรตั้งค่ารูปภาพเล็กเป็น
R.drawable.empty_dice
เริ่มบทเรียนถัดไป:
สําหรับลิงก์ไปยัง Codelab อื่นๆ ในหลักสูตรนี้ โปรดดูหน้า Landing Page ของ Codelab ของ Android Kotlin Fundamentals