เกี่ยวกับ Codelab นี้
1 ภาพรวม
ใน Codelab ก่อนหน้า คุณได้ใช้แป้นพิมพ์ลัดแบบคงที่เพื่อใช้ Intent ในตัว (BII) ที่ใช้กันโดยทั่วไปในแอปตัวอย่าง นักพัฒนาแอป Android ใช้การดำเนินการของแอปเพื่อเพิ่มฟังก์ชันการทำงานของแอปให้กับ Google Assistant
ทางลัดแบบคงที่จะมาพร้อมกับแอปและจะอัปเดตได้โดยการเผยแพร่แอปเวอร์ชันใหม่เท่านั้น คุณจะเปิดใช้ฟังก์ชันเสียงสำหรับองค์ประกอบแบบไดนามิกในแอป เช่น เนื้อหาที่ผู้ใช้สร้างขึ้นได้โดยใช้ทางลัดแบบไดนามิก แอปจะพุชทางลัดแบบไดนามิกหลังจากที่ผู้ใช้ดำเนินการที่เกี่ยวข้อง เช่น สร้างโน้ตใหม่ในแอปติดตามงาน เมื่อใช้การดำเนินการของแอป คุณจะเปิดใช้ทางลัดเหล่านี้เพื่อใช้เสียงได้โดยเชื่อมโยงกับ BII ซึ่งช่วยให้ผู้ใช้เข้าถึงเนื้อหาจาก Assistant ได้โดยพูดคำสั่ง เช่น "Ok Google เปิดรายการซื้อของใน ExampleApp"
รูปที่ 1 หน้าจอแบบขั้นๆ 3 หน้าจอที่แสดงงานซึ่งผู้ใช้สร้างขึ้น และ Google Assistant เปิดทางลัดแบบไดนามิกไปยังรายการงานนั้น
สิ่งที่คุณจะสร้าง
ในโค้ดแล็บนี้ คุณจะเปิดใช้ทางลัดแบบไดนามิกสำหรับเสียงในแอป Android รายการสิ่งที่ต้องทําตัวอย่าง ซึ่งจะช่วยให้ผู้ใช้ขอให้ Assistant เปิดรายการในรายการงานที่สร้างในแอปได้ คุณจะทําสิ่งต่างๆ นี้ได้โดยใช้รูปแบบสถาปัตยกรรม Android โดยเฉพาะรูปแบบ repository, service locator และ ViewModel
ข้อกำหนดเบื้องต้น
Codelab นี้สร้างขึ้นจากแนวคิด App Actions ที่พูดถึงใน Codelab ก่อนหน้านี้ โดยเฉพาะ BII และทางลัดแบบคงที่ หากคุณเพิ่งเริ่มใช้ App Actions เราขอแนะนำให้ทำ Codelab ดังกล่าวให้เสร็จก่อนดำเนินการต่อ
นอกจากนี้ โปรดตรวจสอบว่าสภาพแวดล้อมการพัฒนามีการกำหนดค่าต่อไปนี้ก่อนดำเนินการต่อ
- เทอร์มินัลที่ใช้เรียกใช้คําสั่งเชลล์โดยติดตั้ง git แล้ว
- Android Studio เวอร์ชันเสถียรล่าสุด
- อุปกรณ์ Android จริงหรือเสมือนจริงที่มีการเข้าถึงอินเทอร์เน็ต
- บัญชี Google ที่ลงชื่อเข้าใช้ Android Studio, แอป Google และแอป Google Assistant
2 ทำความเข้าใจวิธีการทำงาน
การเปิดใช้งานทางลัดแบบไดนามิกสำหรับการเข้าถึงด้วยเสียงเกี่ยวข้องกับขั้นตอนต่อไปนี้:
- การเชื่อมโยงทางลัดแบบไดนามิกกับ BII ที่มีสิทธิ์
- การเปิดใช้ Assistant เพื่อนำเข้าทางลัดโดยเพิ่มไลบรารีการผสานรวม Google Shortcuts
- การพุชทางลัดทุกครั้งที่ผู้ใช้ทํางานในแอปที่เกี่ยวข้องเสร็จสมบูรณ์
แป้นพิมพ์ลัดการเชื่อมโยง
หากต้องการให้เข้าถึงทางลัดแบบไดนามิกได้จาก Assistant ทางลัดจะต้องเชื่อมโยงกับ BII ที่เกี่ยวข้อง เมื่อมีการทริกเกอร์ BII ที่มีทางลัด Assistant จะจับคู่พารามิเตอร์ในคำขอของผู้ใช้กับคีย์เวิร์ดที่กำหนดไว้ในทางลัดที่เชื่อมโยง เช่น
- ทางลัดที่เชื่อมโยงกับ BII
GET_THING
อาจช่วยให้ผู้ใช้ขอเนื้อหาในแอปที่เฉพาะเจาะจงจาก Assistant ได้โดยตรง * "Ok Google เปิดรายการซื้อของใน ExampleApp" - แป้นพิมพ์ลัดที่เชื่อมโยงกับ
START_EXERCISE
BII ช่วยให้ผู้ใช้ดูเซสชันการออกกำลังกายของตนเองได้ * "Ok Google ขอให้ ExampleApp เริ่มการออกกำลังกายปกติของฉัน"
ดูรายการ BII ที่จัดหมวดหมู่ทั้งหมดได้ที่ข้อมูลอ้างอิงเกี่ยวกับ Intent ในตัว
การส่งทางลัดให้กับ Assistant
หลังจากเชื่อมโยงทางลัดกับ BII แล้ว ขั้นตอนถัดไปคือให้ Assistant นำเข้าทางลัดเหล่านี้โดยเพิ่มไลบรารีการผสานรวมทางลัดของ Google ลงในโปรเจ็กต์ของคุณ เมื่อใช้ไลบรารีนี้ Assistant จะทราบถึงทางลัดแต่ละรายการที่แอปของคุณพุช ช่วยให้ผู้ใช้เปิดทางลัดเหล่านั้นได้โดยใช้วลีทริกเกอร์ของทางลัดใน Assistant
3 เตรียมสภาพแวดล้อมในการพัฒนาซอฟต์แวร์
Codelab นี้ใช้ตัวอย่างแอปรายการสิ่งที่ต้องทำซึ่งสร้างมาสำหรับ Android แอปนี้ช่วยให้ผู้ใช้เพิ่มรายการลงในรายการ ค้นหารายการในรายการงานตามหมวดหมู่ และกรองงานตามสถานะการเสร็จสมบูรณ์ได้ ดาวน์โหลดและเตรียมแอปตัวอย่างโดยกรอกข้อมูลในส่วนนี้ให้ครบถ้วน
ดาวน์โหลดไฟล์ฐาน
เรียกใช้คำสั่งต่อไปนี้เพื่อโคลนที่เก็บ GitHub ของแอปตัวอย่าง
git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git
เมื่อโคลนที่เก็บแล้ว ให้ทำตามขั้นตอนต่อไปนี้เพื่อเปิดที่เก็บใน Android Studio
- ในกล่องโต้ตอบยินดีต้อนรับสู่ Android Studio ให้คลิกนําเข้าโปรเจ็กต์
- เลือกโฟลเดอร์ที่คุณโคลนที่เก็บ
หรือคุณอาจดูเวอร์ชันของแอปตัวอย่างที่แสดงถึง Codelab ที่สมบูรณ์โดยการโคลนสาขา codelab-complete
ของที่เก็บ GitHub ดังนี้
git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git --branch codelab-complete
อัปเดตรหัสแอปพลิเคชัน Android
การอัปเดตรหัสแอปพลิเคชันของแอปจะระบุแอปในอุปกรณ์ทดสอบได้อย่างไม่ซ้ำกัน และหลีกเลี่ยงข้อผิดพลาด "ชื่อแพ็กเกจซ้ำกัน" หากอัปโหลดแอปไปยัง Play Console หากต้องการอัปเดตรหัสแอปพลิเคชัน ให้เปิด app/build.gradle
:
android {
...
defaultConfig {
applicationId "com.MYUNIQUENAME.android.fitactions"
...
}
}
แทนที่ "MYUNIQUENAME" ในช่อง applicationId
ด้วยชื่อที่ไม่ซ้ำกัน
เพิ่มทรัพยากร Dependency ของ API ทางลัด
เพิ่มไลบรารี Jetpack ต่อไปนี้ลงในไฟล์ทรัพยากร app/build.gradle
app/build.gradle
dependencies {
...
// Shortcuts library
implementation "androidx.core:core:1.6.0"
implementation 'androidx.core:core-google-shortcuts:1.0.1'
...
}
ทดสอบแอปในอุปกรณ์
ก่อนทำการเปลี่ยนแปลงอื่นๆ กับแอป ควรเห็นภาพว่าแอปตัวอย่างทำอะไรได้บ้าง หากต้องการเรียกใช้แอปบนโปรแกรมจำลอง ให้ทำตามขั้นตอนต่อไปนี้
- ใน Android Studio ให้เลือกเรียกใช้ > เรียกใช้แอป หรือคลิกเรียกใช้
ในแถบเครื่องมือ
- ในกล่องโต้ตอบเลือกเป้าหมายการติดตั้งใช้งาน ให้เลือกอุปกรณ์แล้วคลิกตกลง เวอร์ชันระบบปฏิบัติการที่แนะนำคือ Android 10 (API ระดับ 30) ขึ้นไป แม้ว่า App Actions จะทำงานในอุปกรณ์ตั้งแต่ Android 5 (API ระดับ 21) ลงไปได้ก็ตาม
- กดปุ่มหน้าแรกค้างไว้เพื่อตั้งค่า Assistant และยืนยันว่าใช้งานได้ คุณจะต้องลงชื่อเข้าใช้ Assistant ในอุปกรณ์ หากยังไม่ได้ดำเนินการ
ดูข้อมูลเพิ่มเติมเกี่ยวกับอุปกรณ์เสมือนของ Android ได้ที่หัวข้อสร้างและจัดการอุปกรณ์เสมือน
สำรวจแอปโดยย่อเพื่อดูว่าแอปทำอะไรได้บ้าง การแตะไอคอนเครื่องหมายบวกจะสร้างรายการงานใหม่ และรายการเมนูที่ด้านขวาบนจะช่วยให้คุณค้นหาและกรองรายการงานตามสถานะการเสร็จสมบูรณ์ได้
4 สร้างคลาสที่เก็บทางลัด
หลายคลาสในแอปตัวอย่างของเราจะเรียกใช้ ShortcutManagerCompat
API เพื่อพุชและจัดการทางลัดแบบไดนามิก คุณจะใช้ที่เก็บข้อมูลเพื่อให้คลาสโปรเจ็กต์จัดการทางลัดแบบไดนามิกได้อย่างง่ายดาย เพื่อลดโค้ดที่ซ้ำกัน
รูปแบบการออกแบบที่เก็บมี API ที่ดูสะอาดตาสำหรับการจัดการทางลัด ข้อดีของที่เก็บคือรายละเอียดของ API ที่สำคัญจะอยู่ใน API ที่น้อยที่สุดในแบบเดียวกัน ใช้งานที่เก็บโดยทำตามขั้นตอนต่อไปนี้
- สร้างคลาส
ShortcutsRepository
เพื่อกำหนด API ของShortcutManagerCompat
- เพิ่มเมธอด
ShortcutsRepository
ลงในเครื่องระบุตำแหน่งบริการของแอป - ลงทะเบียนบริการ
ShortcutRepository
ในแอปพลิเคชันหลัก
สร้างที่เก็บ
สร้างคลาส Kotlin ใหม่ชื่อ ShortcutsRepository
ในแพ็กเกจ com.example.android.architecture.blueprints.todoapp.data.source
คุณจะเห็นแพ็กเกจนี้จัดระเบียบอยู่ในโฟลเดอร์ app/src/main/java
คุณจะใช้คลาสนี้เพื่อติดตั้งใช้งานอินเทอร์เฟซที่มีชุดเมธอดขั้นต่ำซึ่งครอบคลุม Use Case ของโค้ดแล็บ
รูปที่ 2 หน้าต่าง Project Files ของ Android Studio ที่แสดงตำแหน่งของคลาส ShortcutsRepository
วางโค้ดต่อไปนี้ในชั้นเรียนใหม่
package com.example.android.architecture.blueprints.todoapp.data.source
import android.content.Context
import android.content.Intent
import androidx.annotation.WorkerThread
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import com.example.android.architecture.blueprints.todoapp.data.Task
import com.example.android.architecture.blueprints.todoapp.tasks.TasksActivity
private const val GET_THING_KEY = "q"
/**
* ShortcutsRepository provides an interface for managing dynamic shortcuts.
*/
class ShortcutsRepository(val context: Context) {
private val appContext = context.applicationContext
/**
* Pushes a dynamic shortcut. The task ID is used as the shortcut ID.
* The task's title and description are used as shortcut's short and long labels.
* The resulting shortcut corresponds to the GET_THING capability with task's
* title used as BII's "name" argument.
*
* @param task Task object for which to create a shortcut.
*/
@WorkerThread
fun pushShortcut(task: Task) {
// TODO
}
private fun createShortcutCompat(task: Task): ShortcutInfoCompat {
//...
}
/**
* Updates a dynamic shortcut for the provided task. If the shortcut
* associated with this task doesn't exist, this method throws an error.
* This operation may take a few seconds to complete.
*
* @param tasks list of tasks to update.
*/
@WorkerThread
fun updateShortcuts(tasks: List<Task>) {
//...
}
/**
* Removes shortcuts if IDs are known.
*
* @param ids list of shortcut IDs
*/
@WorkerThread
fun removeShortcutsById(ids: List<String>) {
//...
}
/**
* Removes shortcuts associated with the tasks.
*
* @param tasks list of tasks to remove.
*/
@WorkerThread
fun removeShortcuts(tasks: List<Task>) {
//...
}
}
ขั้นตอนถัดไป ให้อัปเดตเมธอด pushShortcut
เพื่อเรียกใช้ ShortcutManagerCompat
API อัปเดตคลาส ShortcutsRepository
ด้วยรหัสต่อไปนี้
ShortcutsRepository.kt
/**
* Pushes a dynamic shortcut for the task. The task's ID is used as a shortcut
* ID. The task's title and description are used as shortcut's short and long
* labels. The created shortcut corresponds to GET_THING capability with task's
* title used as BII's "name" argument.
*
* @param task Task object for which to create a shortcut.
*/
@WorkerThread
fun pushShortcut(task: Task) {
ShortcutManagerCompat.pushDynamicShortcut(appContext, createShortcutCompat(task))
}
ในตัวอย่างโค้ดก่อนหน้านี้ เราส่ง appContext
ไปยัง API นี่เป็นพร็อพเพอร์ตี้คลาสที่มีบริบทแอปพลิเคชัน คุณควรใช้บริบทแอปพลิเคชัน (ไม่ใช่บริบทกิจกรรม) เพื่อหลีกเลี่ยงปัญหาหน่วยความจำรั่วไหล เนื่องจากบริบทอาจเก็บไว้นานกว่าวงจรของกิจกรรมโฮสต์
นอกจากนี้ API ยังกำหนดให้เราส่งออบเจ็กต์ ShortcutInfoCompat
สำหรับออบเจ็กต์ Task ในตัวอย่างโค้ดก่อนหน้านี้ เราดำเนินการนี้ได้ด้วยการเรียกใช้เมธอด createShortcutCompat
ส่วนตัว ซึ่งจะอัปเดตเพื่อสร้างและแสดงผลออบเจ็กต์ ShortcutInfoCompat
หากต้องการดำเนินการ ให้อัปเดตสตับ createShortcutCompat
ด้วยโค้ดต่อไปนี้
ShortcutsRepository.kt
private fun createShortcutCompat(task: Task): ShortcutInfoCompat {
val intent = Intent(appContext, TasksActivity::class.java)
intent.action = Intent.ACTION_VIEW
// Filtering is set based on currentTitle.
intent.putExtra(GET_THING_KEY, task.title)
// A unique ID is required to avoid overwriting an existing shortcut.
return ShortcutInfoCompat.Builder(appContext, task.id)
.setShortLabel(task.title)
.setLongLabel(task.title)
// Call addCapabilityBinding() to link this shortcut to a BII. Enables user to invoke a shortcut using its title in Assistant.
.addCapabilityBinding(
"actions.intent.GET_THING", "thing.name", listOf(task.title))
.setIntent(intent)
.setLongLived(false)
.build()
}
ต้นขั้วฟังก์ชันที่เหลือในคลาสนี้จะจัดการกับการอัปเดตและลบทางลัดแบบไดนามิก เปิดใช้ฟังก์ชันเหล่านี้โดยอัปเดตด้วยรหัสต่อไปนี้
ShortcutsRepository.kt
/**
* Updates a Dynamic Shortcut for the task. If the shortcut associated with this task
* doesn't exist, throws an error. This operation may take a few seconds to complete.
*
* @param tasks list of tasks to update.
*/
@WorkerThread
fun updateShortcuts(tasks: List<Task>) {
val scs = tasks.map { createShortcutCompat(it) }
ShortcutManagerCompat.updateShortcuts(appContext, scs)
}
/**
* Removes shortcuts if IDs are known.
* @param ids list of shortcut IDs
*/
@WorkerThread
fun removeShortcutsById(ids: List<String>) {
ShortcutManagerCompat.removeDynamicShortcuts(appContext, ids)
}
/**
* Removes shortcuts associated with the tasks.
*
* @param tasks list of tasks to remove.
*/
@WorkerThread
fun removeShortcuts(tasks: List<Task>) {
ShortcutManagerCompat.removeDynamicShortcuts (appContext,
tasks.map { it.id })
}
เพิ่มคลาสไปยังตัวระบุตำแหน่งบริการ
เมื่อสร้างคลาส ShortcutsRepository
แล้ว ขั้นตอนถัดไปคือทำให้ออบเจ็กต์ที่สร้างขึ้นใหม่ของคลาสนี้พร้อมใช้งานสำหรับส่วนที่เหลือของแอป แอปนี้จะจัดการการพึ่งพาคลาสโดยใช้รูปแบบ service locator เปิดคลาสตัวระบุบริการโดยใช้เครื่องมือเรียกดูคลาสใน Android Studio โดยไปที่ไปยังส่วนต่างๆ > คลาส แล้วพิมพ์ "ServiceLocator" คลิกไฟล์ Kotlin ที่สร้างขึ้นเพื่อเปิดใน IDE
ที่ด้านบนของ ServiceLocator.kt
ให้วางโค้ดต่อไปนี้เพื่อนำเข้าแพ็กเกจ ShortcutsRepository
และ SuppressLint
ServiceLocator.kt
package com.example.android.architecture.blueprints.todoapp
// ...Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
import android.annotation.SuppressLint
เพิ่มสมาชิกและเมธอดบริการ ShortcutRepository
โดยวางโค้ดต่อไปนี้ลงในส่วนเนื้อหาของ ServiceLocator.kt
ServiceLocator.kt
object ServiceLocator {
// ...
// Only the code immediately below this comment needs to be copied and pasted
// into the body of ServiceLocator.kt:
@SuppressLint("StaticFieldLeak")
@Volatile
var shortcutsRepository: ShortcutsRepository? = null
private fun createShortcutsRepository(context: Context): ShortcutsRepository {
val newRepo = ShortcutsRepository(context.applicationContext)
shortcutsRepository = newRepo
return newRepo
}
fun provideShortcutsRepository(context: Context): ShortcutsRepository {
synchronized(this) {
return shortcutsRepository ?: shortcutsRepository ?: createShortcutsRepository(context)
}
}
}
ลงทะเบียนบริการทางลัด
ขั้นตอนสุดท้ายคือการลงทะเบียนบริการ ShortcutsRepository
ใหม่กับแอปพลิเคชัน ใน Android Studio ให้เปิด TodoApplication.kt
แล้วคัดลอกโค้ดต่อไปนี้ใกล้กับด้านบนของไฟล์
TodoApplication.kt
package com.example.android.architecture.blueprints.todoapp
/// ... Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
ถัดไป ให้ลงทะเบียนบริการโดยเพิ่มโค้ดต่อไปนี้ลงในเนื้อหาของคลาส
TodoApplication.kt
//...
class TodoApplication : Application() {
//...
val shortcutsRepository: ShortcutsRepository
get() = ServiceLocator.provideShortcutsRepository(this)
//...
}
สร้างแอปและตรวจสอบว่าแอปทำงานต่อไป
5 พุชทางลัดใหม่
เมื่อสร้างบริการทางลัดแล้ว คุณก็พร้อมที่จะพุชทางลัดแล้ว เนื่องจากผู้ใช้สร้างเนื้อหา (รายการงาน) ในแอปนี้และคาดหวังว่าจะกลับมาดูเนื้อหาเหล่านั้นในภายหลังได้ เราจะเปิดใช้การเข้าถึงเนื้อหานี้ด้วยเสียงโดยส่งแป้นพิมพ์ลัดแบบไดนามิกที่เชื่อมโยงกับ BII ของ GET_THING
ทุกครั้งที่ผู้ใช้สร้างงานใหม่ ซึ่งจะช่วยให้ Assistant เปิดรายการงานของผู้ใช้โดยตรงเมื่อผู้ใช้เรียกใช้ BII โดยพูดว่า "Ok Google เปิดรายการซื้อของใน SampleApp"
คุณสามารถเปิดใช้ฟังก์ชันนี้ในแอปตัวอย่างโดยทำตามขั้นตอนต่อไปนี้
- การนําเข้าบริการ
ShortcutsRepository
ไปยังคลาสAddEditTaskViewModel
ซึ่งมีหน้าที่จัดการออบเจ็กต์รายการงาน - พุชทางลัดแบบไดนามิกเมื่อผู้ใช้สร้างงานใหม่
นำเข้า ShortcutsRepository
ก่อนอื่นเราจำเป็นต้องทำให้บริการ ShortcutsRepository
พร้อมใช้งานสำหรับ AddEditTaskViewModel
โดยนําเข้าบริการไปยัง ViewModelFactory
ซึ่งเป็นคลาส Factory ที่แอปใช้สร้างอินสแตนซ์ออบเจ็กต์ ViewModel รวมถึง AddEditTaskViewModel
เปิดเครื่องมือเรียกดูคลาสใน Android Studio โดยไปที่ไปยังส่วนต่างๆ > คลาส แล้วพิมพ์ "ViewModelFactory" คลิกไฟล์ Kotlin ที่ได้เพื่อเปิดใน IDE
วางรหัสต่อไปนี้เพื่อนำเข้าแพ็กเกจ ShortcutsRepository
และ SuppressLint
ที่ด้านบนของ ViewModelFactory.kt
ViewModelFactory.kt
package com.example.android.architecture.blueprints.todoapp
// ...Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
จากนั้นแทนที่เนื้อหาของ ViewModelFactory
ด้วยโค้ดต่อไปนี้
ViewModelFactory.kt
/**
* Factory for all ViewModels.
*/
@Suppress("UNCHECKED_CAST")
class ViewModelFactory constructor(
private val tasksRepository: TasksRepository,
private val shortcutsRepository: ShortcutsRepository,
owner: SavedStateRegistryOwner,
defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
) = with(modelClass) {
when {
isAssignableFrom(StatisticsViewModel::class.java) ->
StatisticsViewModel(tasksRepository)
isAssignableFrom(TaskDetailViewModel::class.java) ->
TaskDetailViewModel(tasksRepository)
isAssignableFrom(AddEditTaskViewModel::class.java) ->
AddEditTaskViewModel(tasksRepository, shortcutsRepository)
isAssignableFrom(TasksViewModel::class.java) ->
TasksViewModel(tasksRepository, handle)
else ->
throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
}
} as T
}
ทำการเปลี่ยนแปลง ViewModelFactory
ให้เสร็จโดยเลื่อนขึ้น 1 ชั้น แล้วส่ง ShortcutsRepository
ไปยังตัวสร้างของ Factory เปิดเบราว์เซอร์ไฟล์ของ Android Studio โดยไปที่นำทาง > File และพิมพ์ "FragmentExt.kt" คลิกไฟล์ Kotlin ที่สร้างขึ้นซึ่งอยู่ในแพ็กเกจ util เพื่อเปิดใน IDE
แทนที่เนื้อหาของ FragmentExt.kt
ด้วยโค้ดต่อไปนี้
fun Fragment.getViewModelFactory(): ViewModelFactory {
val taskRepository = (requireContext().applicationContext as TodoApplication).taskRepository
val shortcutsRepository = (requireContext().applicationContext as TodoApplication).shortcutsRepository
return ViewModelFactory(taskRepository, shortcutsRepository, this)
}
พุชทางลัด
เมื่อคลาสการแยกแยะ ShortcutsRepository
พร้อมใช้งานสำหรับคลาส ViewModel
ของแอปตัวอย่าง คุณจะอัปเดต AddEditTaskViewModel
ซึ่งเป็นคลาส ViewModel
ที่รับผิดชอบในการสร้างโน้ต เพื่อส่งแป้นพิมพ์ลัดแบบไดนามิกทุกครั้งที่ผู้ใช้สร้างโน้ตใหม่
ใน Android Studio ให้เปิดเบราว์เซอร์ของชั้นเรียน แล้วพิมพ์ "AddEditTaskViewModel" คลิกไฟล์ Kotlin ที่ได้เพื่อเปิดใน IDE
ก่อนอื่น ให้เพิ่มแพ็กเกจ ShortcutsRepository
ลงในคลาสนี้ด้วยคำสั่งการนําเข้าต่อไปนี้
package com.example.android.architecture.blueprints.todoapp.addedittask
//Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
ถัดไป ให้เพิ่มพร็อพเพอร์ตี้คลาส shortcutsRepository
โดยอัปเดตคอนสตรัคเตอร์ของคลาสด้วยโค้ดต่อไปนี้
AddEditTaskViewModel.kt
//...
/**
* ViewModel for the Add/Edit screen.
*/
class AddEditTaskViewModel(
private val tasksRepository: TasksRepository,
private val shortcutsRepository: ShortcutsRepository
) : ViewModel() {
//...
เมื่อเพิ่มคลาส ShortcutsRepository
แล้ว ให้สร้างฟังก์ชันใหม่ pushShortcut()
เพื่อเรียกคลาสนี้ วางฟังก์ชันส่วนตัวต่อไปนี้ลงในเนื้อหาของ AddEditTaskViewModel
AddEditTaskViewModel.kt
//...
private fun pushShortcut(newTask: Task) = viewModelScope.launch {
shortcutsRepository.pushShortcut(newTask)
}
สุดท้าย ให้ส่งทางลัดแบบไดนามิกใหม่ทุกครั้งที่สร้างงาน แทนที่เนื้อหาของฟังก์ชัน saveTask()
ด้วยโค้ดต่อไปนี้
AddEditTaskViewModel.kt
fun saveTask() {
val currentTitle = title.value
val currentDescription = description.value
if (currentTitle == null || currentDescription == null) {
_snackbarText.value = Event(R.string.empty_task_message)
return
}
if (Task(currentTitle, currentDescription).isEmpty) {
_snackbarText.value = Event(R.string.empty_task_message)
return
}
val currentTaskId = taskId
if (isNewTask || currentTaskId == null) {
val task = Task(currentTitle, currentDescription)
createTask(task)
pushShortcut(task)
} else {
val task = Task(currentTitle, currentDescription, taskCompleted, currentTaskId)
updateTask(task)
}
}
ทดสอบโค้ด
ในที่สุดเราก็พร้อมทดสอบโค้ดของเราแล้ว ในขั้นตอนนี้ คุณจะส่งทางลัดแบบไดนามิกที่เปิดใช้เสียงและตรวจสอบโดยใช้แอป Google Assistant
สร้างตัวอย่างเพลง
การสร้างตัวอย่างโดยใช้ปลั๊กอิน Google Assistant จะทำให้ทางลัดแบบไดนามิกปรากฏใน Assistant ในอุปกรณ์ทดสอบ
ติดตั้งปลั๊กอินทดสอบ
หากยังไม่มีปลั๊กอิน Google Assistant ให้ติดตั้งโดยทำตามขั้นตอนต่อไปนี้ใน Android Studio
- ไปที่ **ไฟล์ > การตั้งค่า (Android Studio > ค่ากำหนดบน MacOS)
- ในส่วนปลั๊กอิน ให้ไปที่ Marketplace แล้วค้นหา "Google Assistant"
- หากไม่พบปลั๊กอินใน Marketplace ให้ดาวน์โหลดปลั๊กอินด้วยตนเองและทำตามวิธีการในหัวข้อติดตั้งปลั๊กอินจากดิสก์
- ติดตั้งเครื่องมือและรีสตาร์ท Android Studio
สร้างตัวอย่าง
สร้างตัวอย่างเพลงโดยทำตามขั้นตอนต่อไปนี้ใน Android Studio
- คลิกเครื่องมือ > Google Assistant > "เครื่องมือทดสอบการดําเนินการของแอป"
- ในช่องชื่อแอป ให้กำหนดชื่อ เช่น "รายการสิ่งที่ต้องทำ"
- คลิกสร้างพรีวิว หากระบบถาม ให้อ่านและยอมรับนโยบายและข้อกำหนดในการให้บริการของการดำเนินการของแอป
รูปที่ 3 แผงการสร้างตัวอย่างของเครื่องมือทดสอบการดำเนินการของแอป
ในระหว่างการทดสอบ ทางลัดแบบไดนามิกที่คุณส่งไปยัง Assistant จะปรากฏใน Assistant โดยจัดระเบียบตามชื่อแอปที่คุณระบุไว้สำหรับเวอร์ชันตัวอย่าง
พุชและตรวจสอบทางลัด
เปิดแอปตัวอย่างอีกครั้งในอุปกรณ์ทดสอบ แล้วทำตามขั้นตอนต่อไปนี้
- สร้างงานใหม่ที่มีชื่อว่า "เริ่ม Codelab"
- เปิดแอป Google Assistant แล้วพูดหรือพิมพ์ว่า "ทางลัดของฉัน"
- แตะแท็บสำรวจ คุณจะเห็นทางลัดตัวอย่าง
- แตะทางลัดเพื่อเรียกใช้ คุณควรเห็นแอปเปิดขึ้นพร้อมชื่อทางลัดที่ป้อนไว้ล่วงหน้าในช่องตัวกรอง ซึ่งช่วยให้ค้นหารายการงานที่ต้องการได้ง่าย
6 (ไม่บังคับ) อัปเดตและลบทางลัด
นอกจากการพุชทางลัดแบบไดนามิกใหม่ๆ ขณะรันไทม์แล้ว แอปยังอัปเดตแป้นพิมพ์ลัดเหล่านั้นเพื่อแสดงสถานะปัจจุบันของเนื้อหาและค่ากำหนดของผู้ใช้ได้ด้วย แนวทางปฏิบัติที่ดีในการอัปเดตทางลัดที่มีอยู่เมื่อใดก็ตามที่ผู้ใช้แก้ไขรายการปลายทาง เช่น การเปลี่ยนชื่องานในแอปตัวอย่างของเรา นอกจากนี้ คุณควรลบทางลัดที่เกี่ยวข้องเมื่อมีการนำทรัพยากรปลายทางออกเพื่อหลีกเลี่ยงการแสดงทางลัดที่ใช้งานไม่ได้แก่ผู้ใช้
อัปเดตทางลัด
แก้ไข AddEditTaskViewModel
เพื่ออัปเดตทางลัดแบบไดนามิกทุกครั้งที่ผู้ใช้เปลี่ยนรายละเอียดของรายการงาน ก่อนอื่น ให้อัปเดตเนื้อหาของคลาสด้วยโค้ดต่อไปนี้เพื่อเพิ่มฟังก์ชันการอัปเดตที่ใช้คลาสที่เก็บของเรา
AddEditTaskViewModel.kt
private fun updateShortcut(newTask: Task) = viewModelScope.launch {
shortcutsRepository.updateShortcuts(listOf(newTask))
}
ถัดไป ให้แก้ไขฟังก์ชัน saveTask()
เพื่อเรียกใช้เมธอดใหม่ทุกครั้งที่มีการอัปเดตงานที่มีอยู่
AddEditTaskViewModel.kt
// Called when clicking on fab.
fun saveTask() {
// ...
// Note: the shortcuts are created/updated in a worker thread.
if (isNewTask || currentTaskId == null) {
//...
} else {
//...
updateShortcut(task)
}
}
ทดสอบรหัสโดยเปิดแอปอีกครั้งและทำตามขั้นตอนต่อไปนี้
- เปลี่ยนชื่อรายการงานที่มีอยู่เป็น "ทำ Codelab ให้เสร็จ"
- เปิด Google Assistant โดยพูดว่า "Ok Google ทางลัดของฉัน"
- แตะแท็บสำรวจ คุณควรเห็นป้ายกำกับแบบสั้นที่อัปเดตสำหรับทางลัดการทดสอบ
นำทางลัดออก
คุณควรนำทางลัดแอปตัวอย่างออกทุกครั้งที่ผู้ใช้ลบงาน ในแอปตัวอย่าง ตรรกะการลบงานอยู่ในคลาส TaskDetailViewModel
ก่อนที่จะอัปเดตชั้นเรียนนี้ เราต้องอัปเดต ViewModelFactory
อีกครั้งเพื่อส่ง shortcutsRepository
ไปยัง TaskDetailViewModel
เปิด ViewModelFactory
แล้วแทนที่เนื้อหาของเมธอดคอนสตรัคเตอร์ด้วยโค้ดต่อไปนี้
//...
class ViewModelFactory constructor(
private val tasksRepository: TasksRepository,
private val shortcutsRepository: ShortcutsRepository,
owner: SavedStateRegistryOwner,
defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
) = with(modelClass) {
when {
isAssignableFrom(StatisticsViewModel::class.java) ->
StatisticsViewModel(tasksRepository)
isAssignableFrom(TaskDetailViewModel::class.java) ->
TaskDetailViewModel(tasksRepository, shortcutsRepository)
isAssignableFrom(AddEditTaskViewModel::class.java) ->
AddEditTaskViewModel(tasksRepository, shortcutsRepository)
isAssignableFrom(TasksViewModel::class.java) ->
TasksViewModel(tasksRepository, handle)
else ->
throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
}
} as T
}
ถัดไป ให้เปิด TaskDetailViewModel
นําเข้าโมดูล ShortcutsRepository
และประกาศตัวแปรอินสแตนซ์สําหรับโมดูลนั้นโดยใช้โค้ดต่อไปนี้
TaskDetailViewModel.kt
package com.example.android.architecture.blueprints.todoapp.taskdetail
...
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
/**
* ViewModel for the Details screen.
*/
class TaskDetailViewModel(
//...
private val shortcutsRepository: ShortcutsRepository
) : ViewModel() {
...
}
สุดท้าย ให้แก้ไขฟังก์ชัน deleteTask()
เพื่อเรียก shortcutsRepository
เพื่อนำทางลัดออกตามรหัสทุกครั้งที่มีการนำงานที่มี taskId
ที่เกี่ยวข้องออก
TaskDetailViewModel.kt
fun deleteTask() = viewModelScope.launch {
_taskId.value?.let {
//...
shortcutsRepository.removeShortcutsById(listOf(it))
}
}
หากต้องการทดสอบโค้ด ให้เปิดแอปอีกครั้งและทำตามขั้นตอนต่อไปนี้
- ลบงานทดสอบ
- เปลี่ยนชื่อรายการงานที่มีอยู่เป็น "Finish Codelab"
- เปิด Google Assistant โดยพูดว่า "Ok Google ทางลัดของฉัน"
- แตะแท็บสำรวจ ตรวจสอบว่าทางลัดการทดสอบไม่ปรากฏขึ้นอีกแล้ว
7 ขั้นตอนถัดไป
ยินดีด้วย ขอขอบคุณที่ช่วยให้ผู้ใช้แอปตัวอย่างของเรากลับไปดูโน้ตที่สร้างได้ง่ายๆ โดยถาม Assistant เกี่ยวกับสิ่งต่างๆ อย่างเช่น "Ok Google เปิดรายการซื้อของใน ExampleApp" ทางลัดจะกระตุ้นให้ผู้ใช้มีส่วนร่วมมากขึ้นโดยทำให้ผู้ใช้เล่นการดำเนินการที่ใช้บ่อยซ้ำในแอปได้ง่ายๆ
หัวข้อที่ครอบคลุม
ในโค้ดแล็บนี้ คุณได้เรียนรู้วิธีต่อไปนี้
- ระบุกรณีการใช้งานการพุชทางลัดแบบไดนามิกในแอป
- ลดความซับซ้อนของโค้ดโดยใช้รูปแบบการออกแบบที่เก็บ Dependency Injection และตัวระบุบริการ
- พุชทางลัดแบบไดนามิกที่ใช้เสียงได้ไปยังเนื้อหาแอปที่ผู้ใช้สร้างขึ้น
- อัปเดตและนำทางลัดที่มีอยู่ออก
สิ่งที่ต้องทำต่อไป
จากที่นี่ คุณสามารถลองปรับเกณฑ์การค้นหาเพิ่มเติมในแอปรายการงานได้ หากต้องการอ้างอิงโปรเจ็กต์ที่เสร็จสมบูรณ์แล้ว ให้ดูที่เก็บ –codelab-complete Branch ใน GitHub
ต่อไปนี้เป็นคำแนะนำบางส่วนสำหรับการดูข้อมูลเพิ่มเติมเกี่ยวกับการขยายแอปนี้ด้วย App Actions
- ดูรายการสิ่งที่ต้องทําตัวอย่างด้วย Google Analytics สําหรับ Firebase เพื่อดูวิธีติดตามประสิทธิภาพของ App Actions
- ไปที่ข้อมูลอ้างอิงเกี่ยวกับ Intent ในตัวของ App Actions เพื่อดูวิธีอื่นๆ ในการขยายแอปไปยัง Assistant
หากต้องการเริ่มต้นใช้งาน Actions on Google ต่อ โปรดดูแหล่งข้อมูลต่อไปนี้
- actions.google.com: เว็บไซต์เอกสารประกอบอย่างเป็นทางการของ Actions on Google
- ดัชนีตัวอย่างการดำเนินการของแอป: แอปและโค้ดตัวอย่างสำหรับสำรวจความสามารถของการดำเนินการของแอป
- Actions on Google GitHub repo: โค้ดและไลบรารีตัวอย่าง
- r/GoogleAssistantDev: ชุมชนอย่างเป็นทางการของ Reddit สําหรับนักพัฒนาซอฟต์แวร์ที่ทํางานร่วมกับ Google Assistant
ติดตามเราใน Twitter ที่ @ActionsOnGoogle เพื่อไม่พลาดประกาศล่าสุด และทวีตไปที่ #appActions เพื่อแชร์สิ่งที่คุณสร้างขึ้น
แบบสำรวจความคิดเห็น
สุดท้าย โปรดทำแบบสำรวจนี้เพื่อแสดงความคิดเห็นเกี่ยวกับประสบการณ์ที่คุณได้รับจากโค้ดแล็บนี้