1. ภาพรวม
ใน Codelab ก่อนหน้า คุณได้ใช้แป้นพิมพ์ลัดแบบคงที่เพื่อนำ Intent ในตัว (BII) ที่ใช้กันโดยทั่วไปในแอปตัวอย่าง นักพัฒนาแอป Android ใช้การดำเนินการของแอปเพื่อเพิ่มฟังก์ชันการทำงานของแอปให้กับ Google Assistant
ทางลัดแบบคงที่จะมาพร้อมกับแอปและจะอัปเดตได้โดยการเผยแพร่แอปเวอร์ชันใหม่เท่านั้น คุณจะเปิดใช้ฟังก์ชันเสียงสำหรับองค์ประกอบแบบไดนามิกในแอป เช่น เนื้อหาที่ผู้ใช้สร้างขึ้นได้โดยใช้ทางลัดแบบไดนามิก แอปจะพุชทางลัดแบบไดนามิกหลังจากที่ผู้ใช้ดำเนินการที่เกี่ยวข้อง เช่น สร้างโน้ตใหม่ในแอปติดตามงาน เมื่อใช้การดำเนินการของแอป คุณจะเปิดใช้ทางลัดเหล่านี้เพื่อใช้เสียงได้โดยเชื่อมโยงกับ BII ซึ่งช่วยให้ผู้ใช้เข้าถึงเนื้อหาจาก Assistant ได้โดยพูดคำสั่ง เช่น "Ok Google เปิดรายการซื้อของใน ExampleApp"
รูปที่ 1 หน้าจอแบบโพรเกรสซีฟ 3 หน้าจอแสดงงานที่ผู้ใช้สร้างขึ้น และ Google Assistant เปิดใช้ทางลัดแบบไดนามิกไปยังรายการงานนั้น
สิ่งที่คุณจะสร้าง
ใน Codelab นี้ คุณจะเปิดใช้ทางลัดแบบไดนามิกสำหรับเสียงในแอป Android สำหรับรายการสิ่งที่ต้องทำได้ ซึ่งจะช่วยให้ผู้ใช้ขอให้ Assistant เปิดรายการงานที่ตนสร้างในแอปได้ คุณดำเนินการนี้ได้โดยใช้รูปแบบสถาปัตยกรรม Android โดยเฉพาะรูปแบบ repository, service locator และ ViewModel
ข้อกำหนดเบื้องต้น
Codelab นี้สร้างขึ้นจากแนวคิด App Actions ที่พูดถึงใน Codelab ก่อนหน้านี้ โดยเฉพาะ BII และทางลัดแบบคงที่ หากคุณเพิ่งเริ่มใช้การดําเนินการของแอป เราขอแนะนําให้ทํา Codelab ให้เสร็จสิ้นก่อนดำเนินการต่อ
นอกจากนี้ โปรดตรวจสอบว่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์ของคุณมีการกำหนดค่าต่อไปนี้ก่อนดำเนินการต่อ
- เทอร์มินัลสำหรับเรียกใช้คำสั่ง Shell ที่ติดตั้ง git
- Android Studio เวอร์ชันเสถียรล่าสุด
- อุปกรณ์ Android จริงหรือเสมือนที่มีการเข้าถึงอินเทอร์เน็ต
- บัญชี Google ที่ลงชื่อเข้าใช้ Android Studio, แอป Google และแอป Google Assistant
2. ทำความเข้าใจวิธีการทำงาน
การเปิดใช้งานทางลัดแบบไดนามิกสำหรับการเข้าถึงด้วยเสียงเกี่ยวข้องกับขั้นตอนต่อไปนี้:
- เชื่อมโยงทางลัดแบบไดนามิกกับ BII ที่มีสิทธิ์
- เปิดใช้ Assistant เพื่อนําเข้าทางลัดโดยเพิ่มไลบรารีการผสานรวมทางลัดของ Google
- กดทางลัดเมื่อใดก็ตามที่ผู้ใช้ทำงานที่เกี่ยวข้องในแอปจนเสร็จสิ้น
แป้นพิมพ์ลัดการเชื่อมโยง
หากต้องการเข้าถึงทางลัดแบบไดนามิกจาก Assistant ทางลัดนั้นจะต้องเชื่อมโยงกับ BII ที่เกี่ยวข้อง เมื่อมีการทริกเกอร์ BII ที่มีทางลัด Assistant จะจับคู่พารามิเตอร์ในคำขอของผู้ใช้กับคีย์เวิร์ดที่กำหนดไว้ในทางลัดที่เชื่อมโยง เช่น
- แป้นพิมพ์ลัดที่เชื่อมโยงกับ
GET_THING
BII ช่วยให้ผู้ใช้ขอเนื้อหาที่เจาะจงในแอปจาก Assistant ได้โดยตรง * "Ok Google เปิดรายการซื้อของใน ExampleApp" - แป้นพิมพ์ลัดที่เชื่อมโยงกับ
ORDER_MENU_ITEM
BII ทำให้ผู้ใช้เล่นคำสั่งซื้อก่อนหน้าซ้ำได้ * "Ok Google สั่งอาหารตามปกติจาก ExampleApp"
โปรดดูข้อมูลอ้างอิง Intent ในตัวเพื่อดูรายการ BII ที่จัดหมวดหมู่ทั้งหมด
การส่งทางลัดให้กับ 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 เลือก Run > เรียกใช้แอปหรือคลิกเรียกใช้ในแถบเครื่องมือ
- เลือกอุปกรณ์ในกล่องโต้ตอบเลือกเป้าหมายการทำให้ใช้งานได้ แล้วคลิกตกลง เวอร์ชันระบบปฏิบัติการที่แนะนำคือ Android 10 (API ระดับ 30) ขึ้นไป แต่การดำเนินการของแอปจะทำงานในอุปกรณ์ตั้งแต่ 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
" คุณจะใช้คลาสนี้เพื่อติดตั้งอินเทอร์เฟซที่มีชุดเมธอดเพียงเล็กน้อยสำหรับกรณีการใช้งาน Codelab
รูปที่ 2 หน้าต่างไฟล์โปรเจ็กต์ Android Studio ที่แสดงตำแหน่งของคลาส UTF-Repository
วางรหัสต่อไปนี้ในชั้นเรียนใหม่
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
แล้ว ขั้นตอนถัดไปคือทำให้ส่วนที่เหลือของแอปสามารถใช้ออบเจ็กต์ที่สร้างอินสแตนซ์ของคลาสนี้ได้ แอปนี้จัดการทรัพยากร Dependency ของคลาสโดยใช้รูปแบบตัวระบุตำแหน่งบริการ เปิดคลาสเครื่องระบุตำแหน่งบริการโดยใช้เบราว์เซอร์คลาสใน Android Studio โดยไปที่นำทาง > คลาส และพิมพ์ "ServiceLocator" คลิกไฟล์ Kotlin ที่ได้เพื่อเปิดใน IDE
วางรหัสต่อไปนี้เพื่อนำเข้าแพ็กเกจ ShortcutsRepository
และ SuppressLint
ที่ด้านบนของ ServiceLocator.kt
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. พุชทางลัดใหม่
เมื่อสร้างบริการทางลัดแล้ว คุณก็พร้อมที่จะพุชทางลัดแล้ว เนื่องจากผู้ใช้สร้างเนื้อหา (รายการงาน) ในแอปนี้และคาดว่าจะกลับมารับชมได้ในภายหลัง เราจึงจะเปิดใช้การเข้าถึงเนื้อหานี้ด้วยเสียง โดยพุชทางลัดแบบไดนามิกที่ผูกกับ GET_THING
BII ทุกครั้งที่ผู้ใช้สร้างงานใหม่ วิธีนี้ช่วยให้ Assistant เปิดตัวผู้ใช้ไปยังรายการงานที่ขอได้โดยตรงเมื่อเรียกใช้ BII โดยถามสิ่งต่างๆ อย่างเช่น "Ok Google เปิดรายการสิ่งที่ต้องซื้อใน SampleApp"
คุณสามารถเปิดใช้ฟังก์ชันนี้ในแอปตัวอย่างโดยทำตามขั้นตอนต่อไปนี้
- นำเข้าบริการ
ShortcutsRepository
ไปยังคลาสAddEditTaskViewModel
ซึ่งมีหน้าที่จัดการออบเจ็กต์รายการงาน - พุชทางลัดแบบไดนามิกเมื่อผู้ใช้สร้างงานใหม่
นำเข้าที่เก็บทางลัด
ก่อนอื่นเราจำเป็นต้องทำให้บริการ ShortcutsRepository
พร้อมใช้งานสำหรับ AddEditTaskViewModel
หากต้องการดำเนินการดังกล่าว ให้นำเข้าบริการไปยัง ViewModelFactory
ซึ่งเป็นคลาสเริ่มต้นที่แอปใช้ในการสร้างอินสแตนซ์ ViewModel ซึ่งรวม AddEditTaskViewModel
ด้วย
เปิดเบราว์เซอร์ของชั้นเรียนใน Android Studio โดยไปที่นำทาง > คลาส และพิมพ์ "ViewModelfactor" คลิกไฟล์ 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
ไปยังเครื่องมือสร้างของโรงงาน เปิดเบราว์เซอร์ไฟล์ของ 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)
}
พุชทางลัด
เมื่อคลาส Abstraction ของ 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 > "App Actions Test Tool"
- ในช่องชื่อแอป ให้กำหนดชื่อ เช่น "รายการสิ่งที่ต้องทำ"
- คลิกสร้างพรีวิว หากระบบถาม ให้อ่านและยอมรับนโยบายและข้อกำหนดในการให้บริการของการดำเนินการของแอป
รูปที่ 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)
}
}
ทดสอบโค้ดของคุณโดยเปิดแอปอีกครั้งและทำตามขั้นตอนต่อไปนี้
- เปลี่ยนชื่อรายการงานที่มีอยู่เป็น "Finish 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" ทางลัดจะกระตุ้นให้ผู้ใช้มีส่วนร่วมมากขึ้นโดยทำให้ผู้ใช้เล่นการดำเนินการที่ใช้บ่อยซ้ำในแอปได้ง่ายๆ
หัวข้อที่ครอบคลุม
คุณได้เรียนรู้วิธีต่อไปนี้ใน Codelab แล้ว
- ระบุกรณีการใช้งานการพุชทางลัดแบบไดนามิกในแอป
- ลดความซับซ้อนของโค้ดโดยใช้รูปแบบการออกแบบที่เก็บ การแทรกทรัพยากร และรูปแบบเครื่องระบุตำแหน่งบริการ
- พุชทางลัดแบบไดนามิกที่ใช้เสียงได้ไปยังเนื้อหาแอปที่ผู้ใช้สร้างขึ้น
- อัปเดตและนำทางลัดที่มีอยู่ออก
สิ่งที่ต้องทำต่อไป
จากที่นี่ คุณสามารถลองปรับเกณฑ์การค้นหาเพิ่มเติมในแอปรายการงานได้ หากต้องการอ้างอิงโปรเจ็กต์ที่เสร็จสมบูรณ์แล้ว ให้ดูที่เก็บ –codelab-complete Branch ใน GitHub
ต่อไปนี้คือคำแนะนำบางส่วนสำหรับข้อมูลเพิ่มเติมเกี่ยวกับการขยายแอปนี้ด้วยการดำเนินการของแอป
- ดูตัวอย่างรายการสิ่งที่ต้องทำด้วย Google Analytics สำหรับ Firebase เพื่อดูวิธีติดตามประสิทธิภาพของการดำเนินการของแอป
- ไปที่ข้อมูลอ้างอิง Intent ในตัวของการดำเนินการของแอปเพื่อดูวิธีอื่นๆ ในการขยายแอปไปยัง Assistant
โปรดสำรวจแหล่งข้อมูลเหล่านี้เพื่อดำเนินการต่อในเส้นทางของ Actions on Google
- actions.google.com: เว็บไซต์เอกสารประกอบอย่างเป็นทางการสำหรับ Actions on Google
- ดัชนีตัวอย่างการดำเนินการของแอป: แอปและโค้ดตัวอย่างสำหรับสำรวจความสามารถของการดำเนินการของแอป
- Actions on Google GitHub repo: โค้ดและไลบรารีตัวอย่าง
- r/GoogleAssistantDev: ชุมชน Reddit อย่างเป็นทางการสำหรับนักพัฒนาซอฟต์แวร์ที่ทำงานร่วมกับ Google Assistant
ติดตามเราบน Twitter @ActionsOnGoogle เพื่อติดตามประกาศล่าสุดของเรา และทวีตไปที่ #appActions เพื่อแชร์สิ่งที่คุณสร้าง
แบบสำรวจความคิดเห็น
สุดท้ายนี้ โปรดกรอกแบบสำรวจนี้เพื่อแสดงความคิดเห็นเกี่ยวกับประสบการณ์ในการใช้งาน Codelab นี้