Codelab นี้เป็นส่วนหนึ่งของหลักสูตรหลักพื้นฐานของ Android Kotlin คุณจะได้รับประโยชน์สูงสุดจากหลักสูตรนี้หากทำตาม Codelab ตามลำดับ Codelab ของหลักสูตรทั้งหมดแสดงอยู่ในหน้า Landing Page ของ Codelab หลักพื้นฐานของ Android Kotlin
บทนำ
แอป Android เกือบทุกแอปที่คุณสร้างจะต้องเชื่อมต่อกับอินเทอร์เน็ตในบางครั้ง ในโค้ดแล็บนี้และโค้ดแล็บต่อๆ ไป คุณจะได้สร้างแอปที่เชื่อมต่อกับเว็บเซอร์วิสเพื่อดึงและแสดงข้อมูล  นอกจากนี้ คุณยังได้ต่อยอดจากสิ่งที่ได้เรียนรู้ใน Codelab ที่ผ่านมาเกี่ยวกับ ViewModel, LiveData และ RecyclerView 
ในโค้ดแล็บนี้ คุณจะได้ใช้ไลบรารีที่ชุมชนพัฒนาขึ้นเพื่อสร้างเลเยอร์เครือข่าย ซึ่งจะช่วยลดความซับซ้อนในการดึงข้อมูลและรูปภาพได้อย่างมาก รวมถึงช่วยให้แอปเป็นไปตามแนวทางปฏิบัติแนะนำบางอย่างของ Android เช่น การโหลดรูปภาพในเธรดเบื้องหลังและการแคชรูปภาพที่โหลดแล้ว สำหรับส่วนแบบอะซิงโครนัสหรือส่วนที่ไม่บล็อกภายในโค้ด เช่น การสื่อสารกับเลเยอร์บริการเว็บ คุณจะต้องแก้ไขแอปให้ใช้โคโรทีนของ Kotlin นอกจากนี้ คุณยังต้องอัปเดตอินเทอร์เฟซผู้ใช้ของแอปหากอินเทอร์เน็ตช้าหรือไม่พร้อมใช้งาน เพื่อให้ผู้ใช้ทราบว่าเกิดอะไรขึ้น
สิ่งที่คุณควรทราบอยู่แล้ว
- วิธีสร้างและใช้ Fragment
 - วิธีไปยังส่วนย่อยต่างๆ และใช้ 
safeArgsเพื่อส่งข้อมูลระหว่างส่วนย่อย - วิธีใช้คอมโพเนนต์สถาปัตยกรรม ซึ่งรวมถึงการแปลง 
ViewModel,ViewModelProvider.Factory,LiveDataและLiveData - วิธีใช้โครูทีนสำหรับงานที่ใช้เวลานาน
 
สิ่งที่คุณจะได้เรียนรู้
- REST Web Service คืออะไร
 - ใช้ไลบรารี Retrofit เพื่อเชื่อมต่อกับเว็บเซอร์วิส REST บนอินเทอร์เน็ตและรับการตอบกลับ
 - ใช้ไลบรารี Moshi เพื่อแยกวิเคราะห์การตอบกลับ JSON เป็นออบเจ็กต์ข้อมูล
 
สิ่งที่คุณต้องทำ
- แก้ไขแอปเริ่มต้นเพื่อส่งคำขอ API ของบริการเว็บและจัดการการตอบกลับ
 - ใช้เลเยอร์เครือข่ายสำหรับแอปโดยใช้ไลบรารี Retrofit
 - แยกวิเคราะห์การตอบกลับ JSON จากบริการเว็บเป็นข้อมูลสดของแอปด้วยไลบรารี Moshi
 - ใช้การรองรับโครูทีนของ Retrofit เพื่อลดความซับซ้อนของโค้ด
 
ในโค้ดแล็บนี้ (และโค้ดแล็บต่อไปนี้) คุณจะได้ทำงานกับแอปเริ่มต้นที่ชื่อ MarsRealEstate ซึ่งแสดงอสังหาริมทรัพย์ที่ขายบนดาวอังคาร แอปนี้เชื่อมต่อกับบริการบนเว็บเพื่อดึงและแสดงข้อมูลพร็อพเพอร์ตี้ รวมถึงรายละเอียดต่างๆ เช่น ราคา และสถานะของพร็อพเพอร์ตี้ว่าพร้อมขายหรือให้เช่าหรือไม่ รูปภาพที่แสดงถึงที่พักแต่ละแห่งเป็นรูปภาพจากดาวอังคารที่ถ่ายจากยานสำรวจดาวอังคารของ NASA

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

.
สถาปัตยกรรมของแอป MarsRealEstate มี 2 โมดูลหลัก ได้แก่
- Fragment ภาพรวมซึ่งมีตารางกริดของรูปภาพพร็อพเพอร์ตี้ขนาดย่อที่สร้างด้วย 
RecyclerView - Fragment มุมมองรายละเอียดที่มีข้อมูลเกี่ยวกับแต่ละพร็อพเพอร์ตี้
 

แอปมี ViewModel สำหรับแต่ละ Fragment สำหรับโค้ดแล็บนี้ คุณจะสร้างเลเยอร์สำหรับบริการเครือข่าย และ ViewModel จะสื่อสารกับเลเยอร์เครือข่ายนั้นโดยตรง  ซึ่งคล้ายกับที่คุณทำใน Codelab ก่อนหน้านี้เมื่อ ViewModel สื่อสารกับฐานข้อมูล Room
ภาพรวม ViewModel มีหน้าที่เรียกเครือข่ายเพื่อรับข้อมูลอสังหาริมทรัพย์บนดาวอังคาร ดีเทล ViewModel มีรายละเอียดสำหรับอสังหาริมทรัพย์บนดาวอังคารชิ้นเดียวที่แสดงในรายละเอียด Fragment  สำหรับ ViewModel แต่ละรายการ คุณจะใช้ LiveData กับการเชื่อมโยงข้อมูลที่รับรู้ถึงวงจรเพื่ออัปเดต UI ของแอปเมื่อข้อมูลเปลี่ยนแปลง  
คุณใช้คอมโพเนนต์การนำทางเพื่อนำทางระหว่าง 2 Fragment และส่งพร็อพเพอร์ตี้ที่เลือกเป็นอาร์กิวเมนต์
ในงานนี้ คุณจะได้ดาวน์โหลดและเรียกใช้แอปเริ่มต้นสำหรับ MarsRealEstate รวมถึงทำความคุ้นเคยกับโครงสร้างของโปรเจ็กต์
ขั้นตอนที่ 1: สำรวจ Fragment และการนำทาง
- ดาวน์โหลดแอปเริ่มต้น MarsRealEstate แล้วเปิดใน Android Studio
 - ตรวจสอบ 
app/java/MainActivity.ktแอปใช้ Fragment สำหรับทั้ง 2 หน้าจอ ดังนั้นงานเดียวของกิจกรรมคือการโหลดเลย์เอาต์ของกิจกรรม - ตรวจสอบ 
app/res/layout/activity_main.xmlเลย์เอาต์กิจกรรมเป็นโฮสต์ของ 2 Fragment ที่กำหนดไว้ในไฟล์การนำทาง เลย์เอาต์นี้จะสร้างอินสแตนซ์ของNavHostFragmentและเครื่องมือควบคุมการนำทางที่เชื่อมโยงกับทรัพยากรnav_graph - เปิด 
app/res/navigation/nav_graph.xmlที่นี่คุณจะเห็นความสัมพันธ์ในการนำทางระหว่าง Fragment ทั้ง 2 รายการ กราฟการนำทางStartDestinationชี้ไปยังoverviewFragmentดังนั้นระบบจะสร้างอินสแตนซ์ของ Fragment ภาพรวมเมื่อเปิดแอป 
ขั้นตอนที่ 2: สำรวจไฟล์ต้นฉบับ Kotlinและการเชื่อมโยงข้อมูล
- ในแผงโปรเจ็กต์ ให้ขยายapp > java โปรดสังเกตว่าแอป MarsRealEstate มีโฟลเดอร์แพ็กเกจ 3 โฟลเดอร์ ได้แก่ 
detail,networkและoverviewซึ่งสอดคล้องกับคอมโพเนนต์หลัก 3 อย่างของแอป ได้แก่ ภาพรวมและรายละเอียดของ Fragment รวมถึงโค้ดสำหรับเลเยอร์เครือข่าย
   - เปิด 
app/java/overview/OverviewFragment.ktOverviewFragmentจะเริ่มต้นOverviewViewModelแบบเลื่อนเวลา ซึ่งหมายความว่าระบบจะสร้างOverviewViewModelเมื่อมีการใช้งานเป็นครั้งแรก - ตรวจสอบเมธอด 
onCreateView()วิธีนี้จะขยายfragment_overviewโดยใช้การเชื่อมโยงข้อมูล ตั้งค่าเจ้าของวงจรการทำงานของการเชื่อมโยงเป็นตัวมันเอง (this) และตั้งค่าตัวแปรviewModelในออบเจ็กต์bindingเป็นตัวมันเอง เนื่องจากเราได้ตั้งค่าเจ้าของวงจรแล้วLiveDataที่ใช้ในการเชื่อมโยงข้อมูลจะสังเกตการเปลี่ยนแปลงโดยอัตโนมัติ และ UI จะได้รับการอัปเดตตามนั้น - เปิด 
app/java/overview/OverviewViewModelเนื่องจากคำตอบเป็นLiveDataและเราได้ตั้งค่าวงจรของตัวแปรการเชื่อมโยงไว้แล้ว การเปลี่ยนแปลงใดๆ ในตัวแปรนี้จะอัปเดต UI ของแอป - ตรวจสอบ
initบล็อก เมื่อสร้างViewModelแล้ว ระบบจะเรียกใช้เมธอดgetMarsRealEstateProperties() - ตรวจสอบเมธอด 
getMarsRealEstateProperties()ในแอปเริ่มต้นนี้ เมธอดนี้มีการตอบกลับตัวยึดตำแหน่ง เป้าหมายของโค้ดแล็บนี้คือการอัปเดตการตอบกลับLiveDataภายในViewModelโดยใช้ข้อมูลจริงที่คุณได้รับจากอินเทอร์เน็ต - เปิด 
app/res/layout/fragment_overview.xmlนี่คือเลย์เอาต์ของ Fragment ภาพรวมที่คุณใช้ในโค้ดแล็บนี้ และมี Data Binding สำหรับ ViewModel โดยจะนำเข้าOverviewViewModelแล้วเชื่อมโยงคำตอบจากViewModelกับTextViewใน Codelab ตอนต่อๆ ไป คุณจะแทนที่มุมมองข้อความด้วยตารางกริดของรูปภาพในRecyclerView - คอมไพล์และเรียกใช้แอป สิ่งที่คุณเห็นในแอปเวอร์ชันปัจจุบันคือการตอบกลับเริ่มต้น "ตั้งค่าการตอบกลับของ Mars API ที่นี่"
 
 
ข้อมูลอสังหาริมทรัพย์ของ Mars จะจัดเก็บไว้ในเว็บเซิร์ฟเวอร์ในรูปแบบบริการเว็บ REST บริการเว็บที่ใช้สถาปัตยกรรม REST สร้างขึ้นโดยใช้คอมโพเนนต์และโปรโตคอลเว็บมาตรฐาน
คุณส่งคำขอไปยังบริการเว็บในลักษณะที่เป็นมาตรฐานผ่าน URI URL ของเว็บที่คุ้นเคยเป็น URI ประเภทหนึ่ง และทั้ง 2 อย่างนี้ใช้แทนกันได้ตลอดหลักสูตรนี้ ตัวอย่างเช่น ในแอปสำหรับบทเรียนนี้ คุณจะดึงข้อมูลทั้งหมดจากเซิร์ฟเวอร์ต่อไปนี้
https://android-kotlin-fun-mars-server.appspot.com
หากคุณพิมพ์ URL ต่อไปนี้ในเบราว์เซอร์ คุณจะเห็นรายการอสังหาริมทรัพย์ทั้งหมดที่พร้อมให้ซื้อบนดาวอังคาร
https://android-kotlin-fun-mars-server.appspot.com/realestate
โดยทั่วไปการตอบสนองจากบริการเว็บจะจัดรูปแบบใน JSON ซึ่งเป็นรูปแบบการแลกเปลี่ยนสำหรับการแสดง Structured Data คุณจะดูข้อมูลเพิ่มเติมเกี่ยวกับ JSON ได้ในงานถัดไป แต่คำอธิบายสั้นๆ คือออบเจ็กต์ JSON เป็นชุดของคู่คีย์-ค่า ซึ่งบางครั้งเรียกว่าพจนานุกรม แฮชแมป หรืออาร์เรย์แบบเชื่อมโยง คอลเล็กชันของออบเจ็กต์ JSON คืออาร์เรย์ JSON และเป็นอาร์เรย์ที่คุณได้รับกลับมาเป็นการตอบกลับจากบริการเว็บ
หากต้องการนำข้อมูลนี้ไปยังแอป แอปของคุณต้องสร้างการเชื่อมต่อเครือข่ายและสื่อสารกับเซิร์ฟเวอร์นั้น จากนั้นรับและแยกวิเคราะห์ข้อมูลการตอบกลับเป็นรูปแบบที่แอปใช้ได้ ในโค้ดแล็บนี้ คุณจะใช้ไลบรารีไคลเอ็นต์ REST ที่ชื่อ Retrofit เพื่อสร้างการเชื่อมต่อนี้
ขั้นตอนที่ 1: เพิ่มการอ้างอิง Retrofit ลงใน Gradle
- เปิด build.gradle (Module: app)
 - ในส่วน 
dependenciesให้เพิ่มบรรทัดต่อไปนี้สำหรับไลบรารี Retrofit 
implementation "com.squareup.retrofit2:retrofit:$version_retrofit"
implementation "com.squareup.retrofit2:converter-scalars:$version_retrofit"
โปรดทราบว่าหมายเลขเวอร์ชันจะกำหนดแยกกันในไฟล์ Gradle ของโปรเจ็กต์ การขึ้นต่อกันแรกคือไลบรารี Retrofit 2 เอง และการขึ้นต่อกันที่ 2 คือตัวแปลงสเกลาร์ Retrofit  ตัวแปลงนี้ช่วยให้ Retrofit แสดงผลลัพธ์ JSON เป็น String ได้ ห้องสมุดทั้ง 2 แห่งทำงานร่วมกัน
- คลิกซิงค์เลยเพื่อสร้างโปรเจ็กต์ใหม่โดยใช้ทรัพยากร Dependency ใหม่
 
ขั้นตอนที่ 2: ใช้ MarsApiService
Retrofit จะสร้าง API เครือข่ายสำหรับแอปโดยอิงตามเนื้อหาจากบริการเว็บ โดยจะดึงข้อมูลจากเว็บเซอร์วิสและกำหนดเส้นทางผ่านไลบรารีตัวแปลงแยกต่างหากที่รู้วิธีถอดรหัสข้อมูลและส่งคืนในรูปแบบของออบเจ็กต์ที่มีประโยชน์ Retrofit มีการรองรับรูปแบบข้อมูลบนเว็บยอดนิยม เช่น XML และ JSON ในตัว ท้ายที่สุดแล้ว Retrofit จะสร้างเลเยอร์เครือข่ายส่วนใหญ่ให้คุณ รวมถึงรายละเอียดที่สำคัญ เช่น การเรียกใช้คำขอในเธรดเบื้องหลัง
คลาส MarsApiService มีเลเยอร์เครือข่ายสำหรับแอป ซึ่งหมายความว่านี่คือ API ที่ ViewModel จะใช้เพื่อสื่อสารกับเว็บเซอร์วิส  นี่คือคลาสที่คุณจะใช้ API ของบริการ Retrofit  
- เปิด 
app/java/network/MarsApiService.ktตอนนี้ไฟล์มีเพียงอย่างเดียวคือค่าคงที่สำหรับ URL ฐานของเว็บเซอร์วิส 
private const val BASE_URL = 
   "https://android-kotlin-fun-mars-server.appspot.com"- ใช้เครื่องมือสร้าง Retrofit เพื่อสร้างออบเจ็กต์ Retrofit ใต้ค่าคงที่นั้น  นำเข้า 
retrofit2.Retrofitและretrofit2.converter.scalars.ScalarsConverterFactoryเมื่อได้รับคำขอ 
private val retrofit = Retrofit.Builder()
   .addConverterFactory(ScalarsConverterFactory.create())
   .baseUrl(BASE_URL)
   .build()
Retrofit ต้องมีอย่างน้อย 2 สิ่งเพื่อสร้าง API ของบริการเว็บ ได้แก่ URI ฐานสำหรับบริการเว็บ และโรงงานตัวแปลง  ตัวแปลงจะบอก Retrofit ว่าจะทำอย่างไรกับข้อมูลที่ได้รับจากเว็บเซอร์วิส  ในกรณีนี้ คุณต้องการให้ Retrofit ดึงข้อมูลการตอบกลับ JSON จากบริการเว็บ และส่งคืนเป็น String  Retrofit มี ScalarsConverter ที่รองรับสตริงและประเภทพื้นฐานอื่นๆ คุณจึงเรียก addConverterFactory() ในเครื่องมือสร้างด้วยอินสแตนซ์ของ ScalarsConverterFactory ได้  สุดท้าย คุณจะเรียกใช้ build() เพื่อสร้างออบเจ็กต์ Retrofit
- กำหนดอินเทอร์เฟซที่กำหนดวิธีที่ Retrofit สื่อสารกับเว็บเซิร์ฟเวอร์โดยใช้คำขอ HTTP ที่ด้านล่างการเรียกใช้ตัวสร้าง Retrofit  นำเข้า 
retrofit2.http.GETและretrofit2.Callเมื่อมีการร้องขอ 
interface MarsApiService {
    @GET("realestate")
    fun getProperties():
            Call<String>
}ตอนนี้เป้าหมายคือการรับสตริงการตอบกลับ JSON จากบริการเว็บ และคุณต้องใช้วิธีเดียวในการดำเนินการดังกล่าว นั่นคือ getProperties()  หากต้องการบอก Retrofit ว่าเมธอดนี้ควรทำอะไร ให้ใช้คำอธิบายประกอบ @GET และระบุเส้นทางหรือปลายทางสำหรับเมธอดของเว็บเซอร์วิสนั้น  ในกรณีนี้ ปลายทางเรียกว่า realestate เมื่อเรียกใช้เมธอด getProperties() Retrofit จะต่อท้ายปลายทาง realestate กับ URL ฐาน (ซึ่งคุณกำหนดไว้ในตัวสร้าง Retrofit) และสร้างออบเจ็กต์ Call ระบบจะใช้ออบเจ็กต์ Call เพื่อเริ่มคำขอ
- ที่ด้านล่าง
MarsApiServiceอินเทอร์เฟซ ให้กำหนดออบเจ็กต์สาธารณะที่ชื่อMarsApiเพื่อเริ่มต้นบริการ Retrofit 
object MarsApi {
    val retrofitService : MarsApiService by lazy { 
       retrofit.create(MarsApiService::class.java) }
}เมธอด Retrofit create() จะสร้างบริการ Retrofit เองด้วยอินเทอร์เฟซ MarsApiService  เนื่องจากการเรียกนี้มีค่าใช้จ่ายสูง และแอปต้องการอินสแตนซ์บริการ Retrofit เพียงรายการเดียว คุณจึงแสดงบริการต่อส่วนอื่นๆ ของแอปโดยใช้ออบเจ็กต์สาธารณะที่ชื่อ MarsApi และเริ่มต้นบริการ Retrofit อย่างช้าๆ ที่นั่น เมื่อตั้งค่าทั้งหมดเสร็จแล้ว ทุกครั้งที่แอปเรียก MarsApi.retrofitService ระบบจะได้รับออบเจ็กต์ Retrofit แบบ Singleton ที่ใช้ MarsApiService
ขั้นตอนที่ 3: เรียกใช้เว็บเซอร์วิสใน OverviewViewModel
- เปิด 
app/java/overview/OverviewViewModel.ktเลื่อนลงไปที่วิธีgetMarsRealEstateProperties() 
private fun getMarsRealEstateProperties() {
   _response.value = "Set the Mars API Response here!"
}นี่คือเมธอดที่คุณจะเรียกใช้บริการ Retrofit และจัดการสตริง JSON ที่ส่งคืน ตอนนี้มีเพียงสตริงตัวยึดตำแหน่งสำหรับการตอบกลับ
- ลบบรรทัดตัวยึดตำแหน่งที่ตั้งค่าการตอบกลับเป็น "ตั้งค่าการตอบกลับจาก Mars API ที่นี่"
 - ใน 
getMarsRealEstateProperties()ให้เพิ่มโค้ดที่แสดงด้านล่าง นำเข้าretrofit2.Callbackและcom.example.android.marsrealestate.network.MarsApiเมื่อมีการร้องขอ
เมธอดMarsApi.retrofitService.getProperties()จะแสดงผลออบเจ็กต์Callจากนั้นคุณจะเรียกใช้enqueue()ในออบเจ็กต์นั้นเพื่อเริ่มคำขอเครือข่ายในเธรดเบื้องหลังได้ 
MarsApi.retrofitService.getProperties().enqueue( 
   object: Callback<String> {
})- คลิกคำว่า 
objectซึ่งขีดเส้นใต้สีแดง เลือกโค้ด > ใช้เมธอด เลือกทั้งonResponse()และonFailure()จากรายการ
Android Studio จะเพิ่มโค้ดที่มี TODO ในแต่ละเมธอด 
override fun onFailure(call: Call<String>, t: Throwable) {
       TODO("not implemented") 
}
override fun onResponse(call: Call<String>, 
   response: Response<String>) {
       TODO("not implemented") 
}- ใน 
onFailure()ให้ลบ TODO และตั้งค่า_responseเป็นข้อความแสดงข้อผิดพลาด ดังที่แสดงด้านล่าง_responseคือLiveDataสตริงที่กำหนดสิ่งที่แสดงในมุมมองข้อความ แต่ละสถานะต้องอัปเดต_responseLiveData
ระบบจะเรียกใช้การเรียกกลับonFailure()เมื่อการตอบกลับของเว็บเซอร์วิสล้มเหลว สำหรับการตอบกลับนี้ ให้ตั้งค่าสถานะ_responseเป็น"Failure: "ต่อท้ายด้วยข้อความจากอาร์กิวเมนต์Throwable 
override fun onFailure(call: Call<String>, t: Throwable) {
   _response.value = "Failure: " + t.message
}- ใน 
onResponse()ให้ลบ TODO และตั้งค่า_responseเป็นเนื้อหาการตอบกลับ ระบบจะเรียกใช้onResponse()การเรียกกลับเมื่อคำขอสำเร็จและเว็บเซอร์วิสส่งการตอบกลับ 
override fun onResponse(call: Call<String>, 
   response: Response<String>) {
      _response.value = response.body()
}ขั้นตอนที่ 4: กำหนดสิทธิ์อินเทอร์เน็ต
- คอมไพล์และเรียกใช้แอป MarsRealEstate โปรดทราบว่าแอปจะปิดทันทีพร้อมข้อผิดพลาด 
   - คลิกแท็บ Logcat ใน Android Studio และจดบันทึกข้อผิดพลาดในบันทึก ซึ่งเริ่มต้นด้วยบรรทัดต่อไปนี้
 
Process: com.example.android.marsrealestate, PID: 10646 java.lang.SecurityException: Permission denied (missing INTERNET permission?)
ข้อความแสดงข้อผิดพลาดจะแจ้งให้คุณทราบว่าแอปอาจไม่มีสิทธิ์ INTERNET การเชื่อมต่ออินเทอร์เน็ตทำให้เกิดข้อกังวลด้านความปลอดภัย แอปจึงไม่มีการเชื่อมต่ออินเทอร์เน็ตโดยค่าเริ่มต้น คุณต้องบอก Android อย่างชัดเจนว่าแอปจำเป็นต้องเข้าถึงอินเทอร์เน็ต
- เปิด 
app/manifests/AndroidManifest.xmlเพิ่มบรรทัดนี้ก่อนแท็ก<application> 
<uses-permission android:name="android.permission.INTERNET" />- คอมไพล์และเรียกใช้แอปอีกครั้ง  หากการเชื่อมต่ออินเทอร์เน็ตทำงานอย่างถูกต้อง คุณจะเห็นข้อความ JSON ที่มีข้อมูลพร็อพเพอร์ตี้ของดาวอังคาร

 - แตะปุ่มย้อนกลับในอุปกรณ์หรือโปรแกรมจำลองเพื่อปิดแอป
 - เปิดโหมดบนเครื่องบินในอุปกรณ์หรือโปรแกรมจำลอง แล้วเปิดแอปอีกครั้งจากเมนู "ล่าสุด" หรือรีสตาร์ทแอปจาก Android Studio
 

- ปิดโหมดบนเครื่องบินอีกครั้ง
 
ตอนนี้คุณได้รับคำตอบ JSON จากบริการเว็บของ Mars ซึ่งเป็นจุดเริ่มต้นที่ดี แต่สิ่งที่คุณต้องการจริงๆ คือออบเจ็กต์ Kotlin ไม่ใช่สตริง JSON ขนาดใหญ่ มีไลบรารีชื่อ Moshi ซึ่งเป็นตัวแยกวิเคราะห์ JSON ของ Android ที่แปลงสตริง JSON เป็นออบเจ็กต์ Kotlin Retrofit มีตัวแปลงที่ใช้ได้กับ Moshi จึงเป็นไลบรารีที่ยอดเยี่ยมสำหรับวัตถุประสงค์ของคุณในที่นี้
ในงานนี้ คุณจะได้ใช้ไลบรารี Moshi กับ Retrofit เพื่อแยกวิเคราะห์การตอบกลับ JSON จากบริการเว็บเป็นออบเจ็กต์ Kotlin ของ Mars Property ที่มีประโยชน์ คุณเปลี่ยนแอปเพื่อให้แสดงจำนวนพร็อพเพอร์ตี้ของดาวอังคารที่แสดงแทนที่จะแสดง JSON ดิบ
ขั้นตอนที่ 1: เพิ่มการอ้างอิงไลบรารี Moshi
- เปิด build.gradle (Module: app)
 - ในส่วนการขึ้นต่อกัน ให้เพิ่มโค้ดที่แสดงด้านล่างเพื่อรวมการขึ้นต่อกันของ Moshi เช่นเดียวกับ Retrofit 
$version_moshiจะกำหนดแยกกันในไฟล์ Gradle ระดับโปรเจ็กต์ การขึ้นต่อกันเหล่านี้จะเพิ่มการรองรับไลบรารี JSON หลักของ Moshi และการรองรับ Kotlin ของ Moshi 
implementation "com.squareup.moshi:moshi:$version_moshi"
implementation "com.squareup.moshi:moshi-kotlin:$version_moshi"- ค้นหาบรรทัดสำหรับตัวแปลงสเกลาร์ Retrofit ในบล็อก 
dependenciesดังนี้ 
implementation "com.squareup.retrofit2:converter-scalars:$version_retrofit"- เปลี่ยนบรรทัดนั้นให้ใช้ 
converter-moshiดังนี้ 
implementation "com.squareup.retrofit2:converter-moshi:$version_retrofit"- คลิกซิงค์เลยเพื่อสร้างโปรเจ็กต์ใหม่โดยใช้ทรัพยากร Dependency ใหม่
 
ขั้นตอนที่ 2: ใช้คลาสข้อมูล MarsProperty
ตัวอย่างรายการในการตอบกลับ JSON ที่คุณได้รับจากบริการเว็บมีลักษณะดังนี้
[{"price":450000,
"id":"424906",
"type":"rent",
"img_src":"http://mars.jpl.nasa.gov/msl-raw-images/msss/01000/mcam/1000ML0044631300305227E03_DXXX.jpg"},
...]การตอบกลับ JSON ที่แสดงด้านบนเป็นอาร์เรย์ ซึ่งระบุด้วยวงเล็บเหลี่ยม  อาร์เรย์มีออบเจ็กต์ JSON ซึ่งอยู่ในเครื่องหมายปีกกา  ออบเจ็กต์แต่ละรายการจะมีชุดคู่ชื่อ-ค่าที่คั่นด้วยโคลอน ชื่อจะอยู่ในเครื่องหมายคำพูด ค่าอาจเป็นตัวเลขหรือสตริง และสตริงจะอยู่ในเครื่องหมายคำพูด เช่น price สำหรับพร็อพเพอร์ตี้นี้คือ $450,000 และ img_src คือ URL ซึ่งเป็นตำแหน่งของไฟล์รูปภาพในเซิร์ฟเวอร์ 
ในตัวอย่างด้านบน โปรดสังเกตว่ารายการพร็อพเพอร์ตี้ของ Mars แต่ละรายการมีคู่คีย์และค่า JSON ดังนี้
price: ราคาของที่พัก Mars เป็นตัวเลขid: รหัสของพร็อพเพอร์ตี้เป็นสตริงtype:"rent"หรือ"buy"img_src: URL ของรูปภาพเป็นสตริง
Moshi จะแยกวิเคราะห์ข้อมูล JSON นี้และแปลงเป็นออบเจ็กต์ Kotlin โดยจะต้องมีคลาสข้อมูล Kotlin เพื่อจัดเก็บผลลัพธ์ที่แยกวิเคราะห์แล้ว ดังนั้นขั้นตอนถัดไปคือการสร้างคลาสดังกล่าว
- เปิด 
app/java/network/MarsProperty.kt - แทนที่คำจำกัดความของคลาส 
MarsPropertyที่มีอยู่ด้วยโค้ดต่อไปนี้ 
data class MarsProperty(
   val id: String, val img_src: String,
   val type: String,
   val price: Double
)โปรดสังเกตว่าตัวแปรแต่ละตัวในคลาส MarsProperty จะสอดคล้องกับชื่อคีย์ในออบเจ็กต์ JSON  หากต้องการจับคู่ประเภทใน JSON คุณต้องใช้ออบเจ็กต์ String สำหรับค่าทั้งหมด ยกเว้น price ซึ่งเป็น Double  Double ใช้แทนตัวเลข JSON ใดก็ได้
เมื่อ Moshi แยกวิเคราะห์ JSON ระบบจะจับคู่คีย์ตามชื่อและป้อนค่าที่เหมาะสมลงในออบเจ็กต์ข้อมูล
- แทนที่บรรทัดสำหรับ
img_srcด้วยบรรทัดที่แสดงด้านล่าง นำเข้าcom.squareup.moshi.Jsonเมื่อได้รับคำขอ 
@Json(name = "img_src") val imgSrcUrl: String,บางครั้งชื่อคีย์ในการตอบกลับ JSON อาจทำให้พร็อพเพอร์ตี้ Kotlin สับสน หรืออาจไม่ตรงกับรูปแบบการเขียนโค้ดของคุณ เช่น ในไฟล์ JSON คีย์ img_src ใช้ขีดล่าง ในขณะที่พร็อพเพอร์ตี้ Kotlin มักใช้อักษรตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก ("Camel Case") 
หากต้องการใช้ชื่อตัวแปรในคลาสข้อมูลที่แตกต่างจากชื่อคีย์ในการตอบกลับ JSON ให้ใช้คำอธิบายประกอบ @Json ในตัวอย่างนี้ ชื่อของตัวแปรในคลาสข้อมูลคือ imgSrcUrl ระบบจะแมปตัวแปรกับแอตทริบิวต์ JSON img_src โดยใช้ @Json(name = "img_src")
ขั้นตอนที่ 3: อัปเดต MarsApiService และ OverviewViewModel
เมื่อมีคลาสข้อมูล MarsProperty แล้ว คุณจะอัปเดต Network API และ ViewModel เพื่อรวมข้อมูล Moshi ได้  
- เปิด 
network/MarsApiService.ktคุณอาจเห็นข้อผิดพลาดเกี่ยวกับคลาสที่ขาดหายไปสำหรับScalarsConverterFactoryเนื่องจากการเปลี่ยนแปลงการขึ้นต่อกันของ Retrofit ที่คุณทำในขั้นตอนที่ 1 คุณแก้ไขข้อผิดพลาดเหล่านั้นได้ในเร็วๆ นี้ - ที่ด้านบนของไฟล์ ก่อนตัวสร้าง Retrofit ให้เพิ่มโค้ดต่อไปนี้เพื่อสร้างอินสแตนซ์ Moshi  นำเข้า 
com.squareup.moshi.Moshiและcom.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactoryเมื่อได้รับคำขอ 
private val moshi = Moshi.Builder()
   .add(KotlinJsonAdapterFactory())
   .build()เช่นเดียวกับที่ทำกับ Retrofit คุณจะสร้างออบเจ็กต์ moshi ที่นี่โดยใช้ตัวสร้าง Moshi  หากต้องการให้คำอธิบายประกอบของ Moshi ทำงานกับ Kotlin ได้อย่างถูกต้อง ให้เพิ่ม KotlinJsonAdapterFactory แล้วเรียกใช้ build()  
- เปลี่ยนตัวสร้าง Retrofit ให้ใช้ 
MoshiConverterFactoryแทนScalarConverterFactoryและส่งอินสแตนซ์moshiที่คุณเพิ่งสร้าง นำเข้าretrofit2.converter.moshi.MoshiConverterFactoryเมื่อได้รับคำขอ 
private val retrofit = Retrofit.Builder()
   .addConverterFactory(MoshiConverterFactory.create(moshi))
   .baseUrl(BASE_URL)
   .build()- ลบการนำเข้าสำหรับ 
ScalarConverterFactoryด้วย 
โค้ดที่จะลบ
import retrofit2.converter.scalars.ScalarsConverterFactory- อัปเดตอินเทอร์เฟซ 
MarsApiServiceเพื่อให้ Retrofit แสดงรายการออบเจ็กต์MarsPropertyแทนที่จะแสดงCall<String> 
interface MarsApiService {
   @GET("realestate")
   fun getProperties():
      Call<List<MarsProperty>>
}- เปิด 
OverviewViewModel.ktเลื่อนลงไปที่การเรียกใช้getProperties().enqueue()ในเมธอดgetMarsRealEstateProperties() - เปลี่ยนอาร์กิวเมนต์เป็น 
enqueue()จากCallback<String>เป็นCallback<List<MarsProperty>>นำเข้าcom.example.android.marsrealestate.network.MarsPropertyเมื่อได้รับคำขอ 
MarsApi.retrofitService.getProperties().enqueue( 
   object: Callback<List<MarsProperty>> {- ใน 
onFailure()ให้เปลี่ยนอาร์กิวเมนต์จากCall<String>เป็นCall<List<MarsProperty>> 
override fun onFailure(call: Call<List<MarsProperty>>, t: Throwable) {- ทำการเปลี่ยนแปลงเดียวกันกับทั้ง 2 อาร์กิวเมนต์ใน 
onResponse(): 
override fun onResponse(call: Call<List<MarsProperty>>, 
   response: Response<List<MarsProperty>>) {- ในเนื้อหาของ 
onResponse()ให้แทนที่การมอบหมายที่มีอยู่ให้กับ_response.valueด้วยการมอบหมายที่แสดงด้านล่าง เนื่องจากตอนนี้response.body()เป็นรายการออบเจ็กต์MarsPropertyขนาดของรายการนั้นจึงเป็นจํานวนพร็อพเพอร์ตี้ที่แยกวิเคราะห์แล้ว ข้อความตอบกลับนี้จะพิมพ์จำนวนพร็อพเพอร์ตี้ดังกล่าว 
_response.value = 
   "Success: ${response.body()?.size} Mars properties retrieved"- ตรวจสอบว่าโหมดบนเครื่องบินปิดอยู่  คอมไพล์และเรียกใช้แอป คราวนี้ข้อความควรแสดงจำนวนพร็อพเพอร์ตี้ที่ส่งคืนจากเว็บเซอร์วิส:

 
ตอนนี้บริการ Retrofit API กำลังทำงานอยู่ แต่ใช้การเรียกกลับที่มีเมธอดการเรียกกลับ 2 รายการที่คุณต้องใช้ โดยวิธีหนึ่งจะจัดการความสำเร็จและอีกวิธีหนึ่งจะจัดการความล้มเหลว และผลลัพธ์ที่ล้มเหลวจะรายงานข้อยกเว้น โค้ดจะมีประสิทธิภาพมากขึ้นและอ่านง่ายขึ้นหากคุณใช้โครูทีนกับการจัดการข้อยกเว้นแทนการใช้โค้ดเรียกกลับ Retrofit มีไลบรารีที่ผสานรวมโครูทีน
ในงานนี้ คุณจะแปลงบริการเครือข่ายและ ViewModel ให้ใช้โครูทีน  
ขั้นตอนที่ 1: เพิ่มการอ้างอิงของโครูทีน
- เปิด build.gradle (Module: app)
 - ในส่วนการขึ้นต่อกัน ให้เพิ่มการรองรับไลบรารีโครูทีนหลักของ Kotlin และไลบรารีโครูทีน Retrofit ดังนี้
 
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version_kotlin_coroutines" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$version_kotlin_coroutines" implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:$version_retrofit_coroutines_adapter"
- คลิกซิงค์เลยเพื่อสร้างโปรเจ็กต์ใหม่โดยใช้ทรัพยากร Dependency ใหม่
 
ขั้นตอนที่ 2: อัปเดต MarsApiService และ OverviewViewModel
- ใน 
MarsApiService.ktให้อัปเดตเครื่องมือสร้าง Retrofit เพื่อใช้CoroutineCallAdapterFactoryตอนนี้เครื่องมือสร้างแบบเต็มจะมีลักษณะดังนี้ 
private val retrofit = Retrofit.Builder()
        .addConverterFactory(MoshiConverterFactory.create(moshi))
        .addCallAdapterFactory(CoroutineCallAdapterFactory())
        .baseUrl(BASE_URL)
        .build()Call Adapter ช่วยให้ Retrofit สร้าง API ที่แสดงผลอย่างอื่นที่ไม่ใช่คลาส Call เริ่มต้นได้  ในกรณีนี้ CoroutineCallAdapterFactory จะช่วยให้เราแทนที่ออบเจ็กต์ Call ที่ getProperties() แสดงผลด้วยออบเจ็กต์ Deferred แทนได้
- ในวิธี 
getProperties()ให้เปลี่ยนCall<List<MarsProperty>>เป็นDeferred<List<MarsProperty>>นำเข้าkotlinx.coroutines.Deferredเมื่อได้รับคำขอgetProperties()วิธีการแบบเต็มมีลักษณะดังนี้ 
@GET("realestate")
fun getProperties():
   Deferred<List<MarsProperty>>อินเทอร์เฟซ Deferred จะกำหนดงานโครูทีนที่แสดงผลค่าผลลัพธ์ (Deferred สืบทอดมาจาก Job) อินเทอร์เฟซ Deferred มีเมธอดที่ชื่อ await() ซึ่งทำให้โค้ดรอโดยไม่บล็อกจนกว่าค่าจะพร้อม แล้วจึงแสดงผลค่านั้น 
- เปิด 
OverviewViewModel.ktเพิ่มงานของโครูทีนก่อนบล็อกinitดังนี้ 
private var viewModelJob = Job()- สร้างขอบเขตของโครูทีนสำหรับงานใหม่นั้นโดยใช้ตัวจัดส่งหลัก
 
private val coroutineScope = CoroutineScope(
   viewModelJob + Dispatchers.Main )Dispatchers.Main Dispatcher ใช้เธรด UI สำหรับการทำงาน  เนื่องจาก Retrofit ทำงานทั้งหมดในเธรดเบื้องหลัง จึงไม่มีเหตุผลที่จะใช้เธรดอื่นสำหรับขอบเขต ซึ่งจะช่วยให้คุณอัปเดตมูลค่าของ MutableLiveData ได้อย่างง่ายดายเมื่อได้รับผลลัพธ์
- ลบโค้ดทั้งหมดภายใน 
getMarsRealEstateProperties()ในที่นี้ คุณจะใช้โครูทีนแทนการเรียกใช้enqueue()รวมถึงการเรียกกลับonFailure()และonResponse() - ภายใน 
getMarsRealEstateProperties()ให้เรียกใช้โครูทีน 
coroutineScope.launch { 
}
หากต้องการใช้ออบเจ็กต์ Deferred ที่ Retrofit แสดงผลสำหรับงานเครือข่าย คุณต้องอยู่ในโครูทีน ดังนั้นที่นี่คุณจึงเปิดโครูทีนที่เพิ่งสร้างขึ้น  คุณยังคงเรียกใช้โค้ดในเทรดหลัก แต่ตอนนี้คุณอนุญาตให้โครูทีนจัดการการทำงานพร้อมกันแล้ว
- ภายในบล็อกการเปิดตัว ให้เรียกใช้ 
getProperties()ในออบเจ็กต์retrofitServiceดังนี้ 
var getPropertiesDeferred = MarsApi.retrofitService.getProperties()การเรียก getProperties() จากบริการ MarsApi จะสร้างและเริ่มการเรียกเครือข่ายในเธรดเบื้องหลัง โดยจะแสดงออบเจ็กต์ Deferred สำหรับงานนั้น 
- นอกจากนี้ ภายในบล็อกการเปิดตัว ให้เพิ่มบล็อก 
try/catchเพื่อจัดการข้อยกเว้น 
try {
} catch (e: Exception) {
  
}- ภายในบล็อก 
try {}ให้เรียกใช้await()ในออบเจ็กต์Deferredดังนี้ 
var listResult = getPropertiesDeferred.await()การเรียก await() ในออบเจ็กต์ Deferred จะแสดงผลลัพธ์จากการเรียกเครือข่ายเมื่อค่าพร้อมใช้งาน await() เมธอดนี้ไม่บล็อก ดังนั้นบริการ Mars API จะดึงข้อมูลจากเครือข่ายโดยไม่บล็อกเธรดปัจจุบัน ซึ่งเป็นสิ่งสำคัญเนื่องจากเราอยู่ในขอบเขตของ UI เธรด เมื่อดำเนินการเสร็จแล้ว โค้ดจะดำเนินการต่อจากจุดที่หยุดไว้  ซึ่งอยู่ภายใน try {} เพื่อให้คุณตรวจพบข้อยกเว้นได้  
- นอกจากนี้ ภายในบล็อก 
try {}หลังจากเมธอดawait()ให้อัปเดตข้อความตอบกลับสำหรับการตอบกลับที่สำเร็จ ดังนี้ 
_response.value = 
   "Success: ${listResult.size} Mars properties retrieved"- ภายในบล็อก 
catch {}ให้จัดการการตอบกลับที่ล้มเหลว ดังนี้ 
_response.value = "Failure: ${e.message}"ตอนนี้เมธอด 
The complete getMarsRealEstateProperties() มีลักษณะดังนี้
private fun getMarsRealEstateProperties() {
   coroutineScope.launch {
       var getPropertiesDeferred = 
          MarsApi.retrofitService.getProperties()
       try {          
           _response.value = 
              "Success: ${listResult.size} Mars properties retrieved"
       } catch (e: Exception) {
           _response.value = "Failure: ${e.message}"
       }
   }
}- ที่ด้านล่างของคลาส ให้เพิ่ม
onCleared()การเรียกกลับด้วยโค้ดนี้ 
override fun onCleared() {
   super.onCleared()
   viewModelJob.cancel()
}การโหลดข้อมูลควรหยุดเมื่อทำลาย ViewModel เนื่องจาก OverviewFragment ที่ใช้ ViewModel นี้จะหายไป หากต้องการหยุดการโหลดเมื่อ ViewModel ถูกทำลาย ให้แทนที่ onCleared() เพื่อยกเลิกงาน
- คอมไพล์และเรียกใช้แอป คุณจะได้รับผลลัพธ์เช่นเดียวกับในงานก่อนหน้า (รายงานจำนวนพร็อพเพอร์ตี้) แต่มีโค้ดและการจัดการข้อผิดพลาดที่ตรงไปตรงมายิ่งขึ้น
 
โปรเจ็กต์ Android Studio: MarsRealEstateNetwork
บริการเว็บ REST
- บริการบนเว็บคือบริการบนอินเทอร์เน็ตที่ช่วยให้แอปของคุณส่งคำขอและรับข้อมูลกลับมาได้
 - เว็บเซอร์วิสทั่วไปใช้สถาปัตยกรรม REST บริการเว็บที่ใช้สถาปัตยกรรม REST เรียกว่าบริการ RESTful บริการเว็บ RESTful สร้างขึ้นโดยใช้คอมโพเนนต์และโปรโตคอลเว็บมาตรฐาน
 - คุณส่งคำขอไปยังเว็บเซอร์วิส REST ในลักษณะที่เป็นมาตรฐานผ่าน URI
 - หากต้องการใช้บริการเว็บ แอปต้องสร้างการเชื่อมต่อเครือข่ายและสื่อสารกับบริการ จากนั้นแอปต้องรับและแยกวิเคราะห์ข้อมูลการตอบกลับเป็นรูปแบบที่แอปใช้ได้
 - ไลบรารี Retrofit เป็นไลบรารีของไคลเอ็นต์ที่ช่วยให้แอปส่งคำขอไปยังเว็บเซอร์วิส REST ได้
 - ใช้ตัวแปลงเพื่อบอก Retrofit ว่าจะทำอะไรกับข้อมูลที่ส่งไปยังเว็บเซอร์วิสและรับกลับจากเว็บเซอร์วิส  เช่น 
ScalarsConverterตัวแปลงจะถือว่าข้อมูลบริการเว็บเป็นStringหรือไพรมิทีฟอื่นๆ - หากต้องการให้แอปเชื่อมต่ออินเทอร์เน็ตได้ ให้เพิ่ม
"android.permission.INTERNET"สิทธิ์ใน Android Manifest 
การแยกวิเคราะห์ JSON
- การตอบกลับจากบริการเว็บมักจะจัดรูปแบบใน JSON ซึ่งเป็นรูปแบบการแลกเปลี่ยนทั่วไปสำหรับการแสดงข้อมูลที่มีโครงสร้าง
 - ออบเจ็กต์ JSON คือคอลเล็กชันของคู่คีย์-ค่า บางครั้งเราเรียกคอลเล็กชันนี้ว่าพจนานุกรม แฮชแมป หรืออาร์เรย์แบบเชื่อมโยง
 - คอลเล็กชันของออบเจ็กต์ JSON คืออาร์เรย์ JSON คุณจะได้รับอาร์เรย์ JSON เป็นการตอบกลับจากบริการเว็บ
 - คีย์ในคู่คีย์-ค่าจะอยู่ในเครื่องหมายคำพูด ค่าอาจเป็นตัวเลขหรือสตริงก็ได้ สตริงจะอยู่ในเครื่องหมายคำพูดด้วย
 - ไลบรารี Moshi เป็นตัวแยกวิเคราะห์ JSON ของ Android ที่แปลงสตริง JSON เป็นออบเจ็กต์ Kotlin Retrofit มีตัวแปลงที่ใช้ได้กับ Moshi
 - Moshi จะจับคู่คีย์ในการตอบกลับ JSON กับพร็อพเพอร์ตี้ในออบเจ็กต์ข้อมูลที่มีชื่อเดียวกัน
 - หากต้องการใช้ชื่อพร็อพเพอร์ตี้อื่นสำหรับคีย์ ให้ใส่คำอธิบายประกอบพร็อพเพอร์ตี้นั้นด้วยคำอธิบายประกอบ 
@Jsonและชื่อคีย์ JSON 
Retrofit และ Coroutine
- Call Adapter ช่วยให้ Retrofit สร้าง API ที่แสดงผลอย่างอื่นที่ไม่ใช่คลาส 
Callเริ่มต้นได้ ใช้คลาสCoroutineCallAdapterFactoryเพื่อแทนที่Callด้วยโครูทีนDeferred - ใช้เมธอด 
await()ในออบเจ็กต์Deferredเพื่อให้โค้ดโครูทีนรอโดยไม่บล็อกจนกว่าค่าจะพร้อม แล้วจึงส่งคืนค่า 
หลักสูตร Udacity:
เอกสารประกอบสำหรับนักพัฒนาแอป Android
เอกสารประกอบของ Kotlin:
อื่นๆ:
ส่วนนี้แสดงรายการการบ้านที่เป็นไปได้สำหรับนักเรียน/นักศึกษาที่กำลังทำ Codelab นี้เป็นส่วนหนึ่งของหลักสูตรที่สอนโดยผู้สอน ผู้สอนมีหน้าที่ดำเนินการต่อไปนี้
- มอบหมายการบ้านหากจำเป็น
 - สื่อสารกับนักเรียนเกี่ยวกับวิธีส่งงานที่ได้รับมอบหมาย
 - ให้คะแนนงานการบ้าน
 
ผู้สอนสามารถใช้คำแนะนำเหล่านี้ได้มากน้อยตามที่ต้องการ และควรมีอิสระในการมอบหมายการบ้านอื่นๆ ที่เห็นว่าเหมาะสม
หากคุณกำลังทำ Codelab นี้ด้วยตนเอง โปรดใช้แบบฝึกหัดเหล่านี้เพื่อทดสอบความรู้ของคุณ
ตอบคำถามต่อไปนี้
คำถามที่ 1
Retrofit ต้องการสิ่งสำคัญ 2 อย่างใดในการสร้าง API ของบริการเว็บ
▢ URI ฐานสำหรับบริการเว็บและGETคำค้นหา
▢ URI ฐานสำหรับบริการเว็บและโรงงานตัวแปลง
▢ การเชื่อมต่อเครือข่ายกับเว็บเซอร์วิสและโทเค็นการให้สิทธิ์
▢ โรงงานตัวแปลงและตัวแยกวิเคราะห์สำหรับการตอบกลับ
คำถามที่ 2
ไลบรารี Moshi มีไว้เพื่ออะไร
▢ เพื่อรับข้อมูลจากเว็บเซอร์วิส
▢ เพื่อโต้ตอบกับ Retrofit เพื่อส่งคำขอบริการเว็บ
▢ เพื่อแยกวิเคราะห์การตอบกลับ JSON จากบริการเว็บเป็นออบเจ็กต์ข้อมูล Kotlin
▢ เปลี่ยนชื่อออบเจ็กต์ Kotlin ให้ตรงกับคีย์ในการตอบกลับ JSON
คำถามที่ 3
Retrofit call adapters ใช้เพื่อวัตถุประสงค์ใด
▢ ช่วยให้ Retrofit ใช้โครูทีนได้
▢ ปรับการตอบสนองของบริการเว็บเป็นออบเจ็กต์ข้อมูล Kotlin
▢ เปลี่ยนการเรียก Retrofit เป็นการเรียกเว็บเซอร์วิส
▢ เพิ่มความสามารถในการส่งคืนสิ่งอื่นที่ไม่ใช่คลาส Call เริ่มต้นใน Retrofit
เริ่มบทเรียนถัดไป: 
ดูลิงก์ไปยัง Codelab อื่นๆ ในหลักสูตรนี้ได้ที่หน้า Landing Page ของ Codelab หลักพื้นฐานของ Android Kotlin