รับการอัปเดตตำแหน่งใน Android ด้วย Kotlin

1. ก่อนเริ่มต้น

Android 10 และ 11 ช่วยให้ผู้ใช้ควบคุมการเข้าถึงตำแหน่งของอุปกรณ์โดยแอปได้มากขึ้น

เมื่อแอปที่ทำงานบน Android 11 ขอสิทธิ์เข้าถึงตำแหน่ง ผู้ใช้จะมี 4 ตัวเลือกดังนี้

  • อนุญาตตลอด
  • อนุญาตขณะใช้แอปเท่านั้น (ใน Android 10)
  • ครั้งเดียวเท่านั้น (ใน Android 11)
  • ปฏิเสธ

Android 10

6a1029175b467c77.png

Android 11

73d8cc88c5877c25.png

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

ข้อกำหนดเบื้องต้น

สิ่งที่คุณต้องทำ

  • ทำตามแนวทางปฏิบัติแนะนำสำหรับตำแหน่งใน Android
  • จัดการสิทธิ์เข้าถึงตำแหน่งขณะแอปทำงานอยู่เบื้องหน้า (เมื่อผู้ใช้ขอให้แอปเข้าถึงตำแหน่งของอุปกรณ์ขณะที่แอปกำลังใช้งานอยู่)
  • แก้ไขแอปที่มีอยู่เพื่อเพิ่มการรองรับการขอสิทธิ์เข้าถึงตำแหน่งโดยการเพิ่มโค้ดสำหรับการสมัครรับข้อมูลและยกเลิกการสมัครรับข้อมูลตำแหน่ง
  • เพิ่มการรองรับ Android 10 และ 11 ให้กับแอปโดยเพิ่มตรรกะในการเข้าถึงตำแหน่งในตำแหน่งเบื้องหน้าหรือขณะใช้งาน

สิ่งที่คุณต้องมี

  • Android Studio 3.4 ขึ้นไปเพื่อเรียกใช้โค้ด
  • อุปกรณ์/โปรแกรมจำลองที่ใช้ตัวอย่าง Android 10 และ 11 สำหรับนักพัฒนาซอฟต์แวร์

2. เริ่มต้นใช้งาน

โคลนที่เก็บโปรเจ็กต์เริ่มต้น

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

 git clone https://github.com/android/codelab-while-in-use-location

คุณสามารถไปที่หน้า GitHub ได้โดยตรง

หากไม่มี Git คุณสามารถรับโปรเจ็กต์เป็นไฟล์ ZIP ได้โดยทำดังนี้

นำเข้าโปรเจ็กต์

เปิด Android Studio เลือก "เปิดโปรเจ็กต์ Android Studio ที่มีอยู่" จากหน้าจอต้อนรับ แล้วเปิดไดเรกทอรีโปรเจ็กต์

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

ที่มุมซ้ายบนของหน้าต่างโปรเจ็กต์ คุณควรเห็นสิ่งที่คล้ายกับรูปภาพด้านล่างหากอยู่ในมุมมอง Android (หากอยู่ในมุมมองโปรเจ็กต์ คุณจะต้องขยายโปรเจ็กต์เพื่อดูสิ่งเดียวกัน)

fa825dae96c5dc18.png

มี 2 โฟลเดอร์ (base และ complete) ซึ่งแต่ละโฟลเดอร์เรียกว่า "โมดูล"

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

c2273e7835c0841a.png

รอจนกว่า Android Studio จะจัดทำดัชนีและสร้างโปรเจ็กต์เสร็จก่อนทำการเปลี่ยนแปลงโค้ด ซึ่งจะช่วยให้ Android Studio ดึงคอมโพเนนต์ที่จำเป็นทั้งหมดได้

หากได้รับข้อความแจ้งว่าโหลดซ้ำเพื่อให้การเปลี่ยนแปลงภาษามีผลไหม หรือข้อความที่คล้ายกัน ให้เลือกใช่

ทำความเข้าใจโปรเจ็กต์เริ่มต้น

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

องค์ประกอบหลักๆ มีดังนี้

  • MainActivity—UI สำหรับผู้ใช้เพื่ออนุญาตให้แอปเข้าถึงตำแหน่งของอุปกรณ์
  • LocationService—บริการที่สมัครรับข้อมูลและยกเลิกการสมัครรับข้อมูลการเปลี่ยนแปลงตำแหน่ง และเลื่อนระดับตัวเองเป็นบริการที่ทำงานอยู่เบื้องหน้า (พร้อมการแจ้งเตือน) หากผู้ใช้นำทางออกจากกิจกรรมของแอป คุณเพิ่มรหัสสถานที่ได้ที่นี่
  • Util - เพิ่มฟังก์ชันส่วนขยายสำหรับคลาส Location และบันทึกตำแหน่งใน SharedPreferences (เลเยอร์ข้อมูลที่เรียบง่าย)

การตั้งค่าโปรแกรมจำลอง

ดูข้อมูลเกี่ยวกับการตั้งค่าโปรแกรมจำลอง Android ได้ที่เรียกใช้ในโปรแกรมจำลอง

เรียกใช้โปรเจ็กต์เริ่มต้น

เรียกใช้แอป

  1. เชื่อมต่ออุปกรณ์ Android กับคอมพิวเตอร์หรือเริ่มโปรแกรมจำลอง (ตรวจสอบว่าอุปกรณ์ใช้ Android 10 ขึ้นไป)
  2. ในแถบเครื่องมือ ให้เลือกการกำหนดค่า base จากตัวเลือกแบบเลื่อนลง แล้วคลิกเรียกใช้

99600e9d44527ab.png

  1. คุณจะเห็นแอปต่อไปนี้ปรากฏในอุปกรณ์

99bf1dae46f99af3.png

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

3. การเพิ่มสถานที่

แนวคิด

Codelab นี้มุ่งเน้นที่การแสดงวิธีรับการอัปเดตตำแหน่ง และรองรับ Android 10 และ Android 11 ในที่สุด

อย่างไรก็ตาม ก่อนที่จะเริ่มเขียนโค้ด คุณควรทบทวนพื้นฐานก่อน

ประเภทการเข้าถึงตำแหน่ง

คุณอาจจำตัวเลือกการเข้าถึงตำแหน่ง 4 แบบที่แตกต่างกันได้ตั้งแต่ช่วงต้นของโค้ดแล็บ โดยมีความหมายดังนี้

  • อนุญาตขณะใช้แอปเท่านั้น
  • ตัวเลือกนี้เป็นตัวเลือกที่แนะนำสำหรับแอปส่วนใหญ่ ตัวเลือกนี้เรียกอีกอย่างว่าการเข้าถึง "ขณะใช้งาน" หรือ "เบื้องหน้าเท่านั้น" ซึ่งเพิ่มเข้ามาใน Android 10 และช่วยให้นักพัฒนาแอปดึงข้อมูลตำแหน่งได้เฉพาะในขณะที่แอปกำลังใช้งานอยู่เท่านั้น แอปจะถือว่าใช้งานอยู่หากมีลักษณะตรงตามข้อใดข้อหนึ่งต่อไปนี้
  • กิจกรรมจะปรากฏ
  • บริการที่ทำงานอยู่เบื้องหน้ากำลังทำงานพร้อมการแจ้งเตือนต่อเนื่อง
  • ครั้งเดียวเท่านั้น
  • ตัวเลือกนี้เพิ่มเข้ามาใน Android 11 และเหมือนกับอนุญาตขณะใช้แอปเท่านั้น แต่จะใช้ได้ในระยะเวลาจำกัด ดูข้อมูลเพิ่มเติมได้ที่สิทธิ์แบบครั้งเดียว
  • ปฏิเสธ
  • ตัวเลือกนี้จะป้องกันการเข้าถึงข้อมูลตำแหน่ง
  • อนุญาตตลอด
  • ตัวเลือกนี้อนุญาตให้เข้าถึงตำแหน่งได้ตลอดเวลา แต่ต้องมีสิทธิ์เพิ่มเติมสำหรับ Android 10 ขึ้นไป นอกจากนี้ คุณต้องตรวจสอบว่ามีกรณีการใช้งานที่ถูกต้องและปฏิบัติตามนโยบายตำแหน่ง คุณจะไม่เห็นตัวเลือกนี้ในโค้ดแล็บนี้ เนื่องจากเป็นกรณีการใช้งานที่พบได้น้อยกว่า อย่างไรก็ตาม หากคุณมี Use Case ที่ถูกต้องและต้องการทำความเข้าใจวิธีจัดการตำแหน่งตลอดเวลาอย่างเหมาะสม รวมถึงการเข้าถึงตำแหน่งในเบื้องหลัง โปรดดูตัวอย่าง LocationUpdatesBackgroundKotlin

บริการ บริการที่ทำงานอยู่เบื้องหน้า และการเชื่อมโยง

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

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

เนื่องจาก Codelab นี้มุ่งเน้นเฉพาะการรับข้อมูลอัปเดตตำแหน่ง คุณจึงดูโค้ดทั้งหมดที่ต้องการได้ในคลาส ForegroundOnlyLocationService.kt คุณสามารถเรียกดูชั้นเรียนนั้นและMainActivity.ktเพื่อดูว่าทั้ง 2 อย่างทำงานร่วมกันอย่างไร

ดูข้อมูลเพิ่มเติมได้ที่ภาพรวมของบริการและภาพรวมของบริการที่เชื่อมโยง

สิทธิ์

หากต้องการรับการอัปเดตตำแหน่งจาก NETWORK_PROVIDER หรือ GPS_PROVIDER คุณต้องขอสิทธิ์จากผู้ใช้โดยประกาศสิทธิ์ ACCESS_COARSE_LOCATION หรือ ACCESS_FINE_LOCATION ตามลำดับในไฟล์ Manifest ของ Android หากไม่มีสิทธิ์เหล่านี้ แอปจะขอสิทธิ์เข้าถึงตำแหน่งในรันไทม์ไม่ได้

สิทธิ์เหล่านั้นครอบคลุมกรณีครั้งเดียวเท่านั้นและอนุญาตขณะใช้แอปเท่านั้นเมื่อแอปของคุณใช้ในอุปกรณ์ที่ใช้ Android 10 ขึ้นไป

ตำแหน่ง

แอปของคุณสามารถเข้าถึงชุดบริการตำแหน่งที่รองรับผ่านคลาสในแพ็กเกจ com.google.android.gms.location ได้

ดูคลาสหลักๆ ดังนี้

  • FusedLocationProviderClient
  • ซึ่งเป็นองค์ประกอบหลักของเฟรมเวิร์กตำแหน่ง เมื่อสร้างแล้ว คุณจะใช้เพื่อขอข้อมูลอัปเดตตำแหน่งและรับตำแหน่งที่ทราบล่าสุดได้
  • LocationRequest
  • ซึ่งเป็นออบเจ็กต์ข้อมูลที่มีพารามิเตอร์คุณภาพของบริการสำหรับคำขอ (ช่วงเวลาสำหรับการอัปเดต ลำดับความสำคัญ และความแม่นยำ) ระบบจะส่งค่านี้ไปยัง FusedLocationProviderClient เมื่อคุณขออัปเดตตำแหน่ง
  • LocationCallback
  • ใช้สำหรับการรับการแจ้งเตือนเมื่อตำแหน่งของอุปกรณ์มีการเปลี่ยนแปลงหรือระบุไม่ได้อีกต่อไป ซึ่งจะส่ง LocationResult ที่คุณสามารถรับ Location เพื่อบันทึกลงในฐานข้อมูล

ตอนนี้คุณมีความคิดพื้นฐานเกี่ยวกับสิ่งที่จะทำแล้ว มาเริ่มเขียนโค้ดกันเลย

4. เพิ่มฟีเจอร์ตำแหน่ง

โค้ดแล็บนี้มุ่งเน้นที่ตัวเลือกตำแหน่งที่พบบ่อยที่สุด นั่นคืออนุญาตขณะใช้แอปเท่านั้น

หากต้องการรับข้อมูลอัปเดตตำแหน่ง แอปจะต้องมีกิจกรรมที่มองเห็นได้หรือบริการที่ทำงานในเบื้องหน้า (พร้อมการแจ้งเตือน)

สิทธิ์

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

ไฮไลต์สิทธิ์มีดังนี้ (ไม่ต้องดำเนินการใดๆ ในส่วนนี้)

  1. ประกาศสิทธิ์ที่คุณใช้ใน AndroidManifest.xml
  2. ก่อนที่จะพยายามเข้าถึงข้อมูลตำแหน่ง ให้ตรวจสอบว่าผู้ใช้ได้ให้สิทธิ์แอปของคุณในการดำเนินการดังกล่าวหรือไม่ หากแอปยังไม่ได้รับสิทธิ์ ให้ขอสิทธิ์เข้าถึง
  3. จัดการตัวเลือกสิทธิ์ของผู้ใช้ (คุณดูรหัสนี้ได้ใน MainActivity.kt)

หากค้นหา TODO: Step 1.0, Review Permissions ใน AndroidManifest.xml หรือ MainActivity.kt คุณจะเห็นโค้ดทั้งหมดที่เขียนขึ้นสำหรับสิทธิ์

ดูข้อมูลเพิ่มเติมได้ที่ภาพรวมของสิทธิ์

ตอนนี้มาเริ่มเขียนโค้ดตำแหน่งกัน

ตรวจสอบตัวแปรสำคัญที่จำเป็นสำหรับการอัปเดตตำแหน่ง

ในbaseโมดูล ให้ค้นหา TODO: Step 1.1, Review variables ใน

ForegroundOnlyLocationService.kt ไฟล์

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

// TODO: Step 1.1, Review variables (no changes).
// FusedLocationProviderClient - Main class for receiving location updates.
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient

// LocationRequest - Requirements for the location updates, i.e., how often you
// should receive updates, the priority, etc.
private lateinit var locationRequest: LocationRequest

// LocationCallback - Called when FusedLocationProviderClient has a new Location.
private lateinit var locationCallback: LocationCallback

// Used only for local storage of the last known location. Usually, this would be saved to your
// database, but because this is a simplified sample without a full database, we only need the
// last location to create a Notification if the user navigates away from the app.
private var currentLocation: Location? = null

ตรวจสอบการเริ่มต้น FusedLocationProviderClient

ในbaseโมดูล ให้ค้นหา TODO: Step 1.2, Review the FusedLocationProviderClient ในไฟล์ ForegroundOnlyLocationService.kt โค้ดควรมีลักษณะดังนี้

// TODO: Step 1.2, Review the FusedLocationProviderClient.
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)

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

เริ่มต้น LocationRequest

  1. ในbaseโมดูล ให้ค้นหา TODO: Step 1.3, Create a LocationRequest ในไฟล์ ForegroundOnlyLocationService.kt
  2. เพิ่มโค้ดต่อไปนี้หลังความคิดเห็น

LocationRequestโค้ดการเริ่มต้นจะเพิ่มพารามิเตอร์คุณภาพของบริการเพิ่มเติมที่คุณต้องการสำหรับคำขอ (ช่วงเวลา เวลาในการรอสูงสุด และลำดับความสำคัญ)

// TODO: Step 1.3, Create a LocationRequest.
locationRequest = LocationRequest.create().apply {
   // Sets the desired interval for active location updates. This interval is inexact. You
   // may not receive updates at all if no location sources are available, or you may
   // receive them less frequently than requested. You may also receive updates more
   // frequently than requested if other applications are requesting location at a more
   // frequent interval.
   //
   // IMPORTANT NOTE: Apps running on Android 8.0 and higher devices (regardless of
   // targetSdkVersion) may receive updates less frequently than this interval when the app
   // is no longer in the foreground.
   interval = TimeUnit.SECONDS.toMillis(60)

   // Sets the fastest rate for active location updates. This interval is exact, and your
   // application will never receive updates more frequently than this value.
   fastestInterval = TimeUnit.SECONDS.toMillis(30)

   // Sets the maximum time when batched location updates are delivered. Updates may be
   // delivered sooner than this interval.
   maxWaitTime = TimeUnit.MINUTES.toMillis(2)

   priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
  1. อ่านความคิดเห็นเพื่อทำความเข้าใจวิธีการทำงานของแต่ละรายการ

เริ่มต้น LocationCallback

  1. ในbaseโมดูล ให้ค้นหา TODO: Step 1.4, Initialize the LocationCallback ในไฟล์ ForegroundOnlyLocationService.kt
  2. เพิ่มโค้ดต่อไปนี้หลังความคิดเห็น
// TODO: Step 1.4, Initialize the LocationCallback.
locationCallback = object : LocationCallback() {
    override fun onLocationResult(locationResult: LocationResult) {
        super.onLocationResult(locationResult)

        // Normally, you want to save a new location to a database. We are simplifying
        // things a bit and just saving it as a local variable, as we only need it again
        // if a Notification is created (when the user navigates away from app).
        currentLocation = locationResult.lastLocation

        // Notify our Activity that a new location was added. Again, if this was a
        // production app, the Activity would be listening for changes to a database
        // with new locations, but we are simplifying things a bit to focus on just
        // learning the location side of things.
        val intent = Intent(ACTION_FOREGROUND_ONLY_LOCATION_BROADCAST)
        intent.putExtra(EXTRA_LOCATION, currentLocation)
        LocalBroadcastManager.getInstance(applicationContext).sendBroadcast(intent)

        // Updates notification content if this service is running as a foreground
        // service.
        if (serviceRunningInForeground) {
            notificationManager.notify(
                NOTIFICATION_ID,
                generateNotification(currentLocation))
        }
    }
}

LocationCallbackที่คุณสร้างที่นี่คือการเรียกกลับที่ FusedLocationProviderClient จะเรียกเมื่อมีการอัปเดตตำแหน่งใหม่

ในการเรียกกลับ คุณจะได้รับตำแหน่งล่าสุดก่อนโดยใช้ออบเจ็กต์ LocationResult หลังจากนั้น ให้แจ้งActivityเกี่ยวกับตำแหน่งใหม่โดยใช้การออกอากาศในพื้นที่ (หากเปิดใช้) หรืออัปเดตNotificationหากบริการนี้ทำงานเป็นServiceที่ทำงานอยู่เบื้องหน้า

  1. อ่านความคิดเห็นเพื่อทำความเข้าใจหน้าที่ของแต่ละส่วน

ติดตามการเปลี่ยนแปลงสถานที่

เมื่อเริ่มต้นทุกอย่างแล้ว คุณต้องแจ้งให้ FusedLocationProviderClient ทราบว่าคุณต้องการรับข้อมูลอัปเดต

  1. ในbaseโมดูล ให้ค้นหา Step 1.5, Subscribe to location changes ในไฟล์ ForegroundOnlyLocationService.kt
  2. เพิ่มโค้ดต่อไปนี้หลังความคิดเห็น
// TODO: Step 1.5, Subscribe to location changes.
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())

requestLocationUpdates() จะแจ้งให้ FusedLocationProviderClient ทราบว่าคุณต้องการรับข้อมูลอัปเดตตำแหน่ง

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

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

ยกเลิกการสมัครรับข้อมูลการเปลี่ยนแปลงตำแหน่ง

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

  1. ในbaseโมดูล ให้ค้นหา TODO: Step 1.6, Unsubscribe to location changes ในไฟล์ ForegroundOnlyLocationService.kt
  2. เพิ่มโค้ดต่อไปนี้หลังความคิดเห็น
// TODO: Step 1.6, Unsubscribe to location changes.
val removeTask = fusedLocationProviderClient.removeLocationUpdates(locationCallback)
removeTask.addOnCompleteListener { task ->
   if (task.isSuccessful) {
       Log.d(TAG, "Location Callback removed.")
       stopSelf()
   } else {
       Log.d(TAG, "Failed to remove Location Callback.")
   }
}

removeLocationUpdates() จะตั้งค่างานเพื่อให้ FusedLocationProviderClient ทราบว่าคุณไม่ต้องการรับข้อมูลอัปเดตตำแหน่งสำหรับ LocationCallback อีกต่อไป addOnCompleteListener() จะให้การเรียกกลับสำหรับการดำเนินการให้เสร็จสมบูรณ์และเรียกใช้ Task

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

คุณอาจสงสัยว่าเมื่อใดที่ระบบจะเรียกใช้เมธอดที่มีโค้ดการสมัครรับข้อมูล/ยกเลิกการสมัครรับข้อมูล โดยจะทริกเกอร์ในคลาสหลักเมื่อผู้ใช้แตะปุ่ม หากต้องการดู ให้ไปที่MainActivity.ktชั้นเรียน

เรียกใช้แอป

เรียกใช้แอปจาก Android Studio แล้วลองใช้ปุ่มตำแหน่ง

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

2ae45c4e297e3681.png

d66089bfb532e993.png

5. รองรับ Android 10

ในส่วนนี้ คุณจะเพิ่มการรองรับ Android 10

แอปของคุณสมัครรับข้อมูลการเปลี่ยนแปลงตำแหน่งอยู่แล้ว จึงไม่ต้องดำเนินการใดๆ มากนัก

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

SDK เป้าหมาย 29

  1. ในbaseโมดูล ให้ค้นหา TODO: Step 2.1, Target Android 10 and then Android 11. ในไฟล์ build.gradle
  2. ทำการเปลี่ยนแปลงต่อไปนี้
  3. ตั้งค่า targetSdkVersion เป็น 29

โค้ดควรมีลักษณะดังนี้

android {
   // TODO: Step 2.1, Target Android 10 and then Android 11.
   compileSdkVersion 29
   defaultConfig {
       applicationId "com.example.android.whileinuselocation"
       minSdkVersion 26
       targetSdkVersion 29
       versionCode 1
       versionName "1.0"
   }
...
}

หลังจากดำเนินการนี้แล้ว ระบบจะขอให้คุณซิงค์โปรเจ็กต์ คลิกซิงค์เลย

153f70847e0ec320.png

หลังจากนั้น แอปของคุณก็เกือบพร้อมสำหรับ Android 10 แล้ว

เพิ่มประเภทบริการที่ทำงานอยู่เบื้องหน้า

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

ในโมดูล base ให้ค้นหา TODO: 2.2, Add foreground service type ใน AndroidManifest.xml แล้วเพิ่มโค้ดต่อไปนี้ลงในองค์ประกอบ <service>

android:foregroundServiceType="location"

โค้ดควรมีลักษณะดังนี้

<application>
   ...

   <!-- Foreground services in Android 10+ require type. -->
   <!-- TODO: 2.2, Add foreground service type. -->
   <service
       android:name="com.example.android.whileinuselocation.ForegroundOnlyLocationService"
       android:enabled="true"
       android:exported="false"
       android:foregroundServiceType="location" />
</application>

เท่านี้ก็เรียบร้อย แอปของคุณรองรับตำแหน่งของ Android 10 สำหรับ "ขณะใช้งาน" โดยทำตามแนวทางปฏิบัติแนะนำสำหรับตำแหน่งใน Android

เรียกใช้แอป

เรียกใช้แอปจาก Android Studio แล้วลองใช้ปุ่มตำแหน่ง

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

6a1029175b467c77.png

c7c1d226e49a121.png

39a262b66a275f66.png

6. รองรับ Android 11

ในส่วนนี้ คุณจะกำหนดเป้าหมายเป็น Android 11

ข่าวดีคือคุณไม่จำเป็นต้องเปลี่ยนแปลงไฟล์ใดๆ ยกเว้นไฟล์ build.gradle

SDK เป้าหมาย 11

  1. ในbaseโมดูล ให้ค้นหา TODO: Step 2.1, Target SDK ในไฟล์ build.gradle
  2. ทำการเปลี่ยนแปลงต่อไปนี้
  3. compileSdkVersion ถึง 30
  4. targetSdkVersion ถึง 30

โค้ดควรมีลักษณะดังนี้

android {
   TODO: Step 2.1, Target Android 10 and then Android 11.
   compileSdkVersion 30
   defaultConfig {
       applicationId "com.example.android.whileinuselocation"
       minSdkVersion 26
       targetSdkVersion 30
       versionCode 1
       versionName "1.0"
   }
...
}

หลังจากดำเนินการนี้แล้ว ระบบจะขอให้คุณซิงค์โปรเจ็กต์ คลิกซิงค์เลย

153f70847e0ec320.png

หลังจากนั้น แอปของคุณก็พร้อมสำหรับ Android 11 แล้ว

เรียกใช้แอป

เรียกใช้แอปจาก Android Studio แล้วลองคลิกปุ่ม

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

73d8cc88c5877c25.png

cc98fac6e089bc4.png

7. กลยุทธ์ด้านตำแหน่งสำหรับ Android

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

หน้านี้แสดงแนวทางปฏิบัติแนะนำที่สำคัญบางส่วนเกี่ยวกับการให้สิทธิ์เข้าถึงตำแหน่ง ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีรักษาข้อมูลของผู้ใช้ให้ปลอดภัยได้ที่แนวทางปฏิบัติแนะนำเกี่ยวกับสิทธิ์ของแอป

ขอเฉพาะสิทธิ์ที่จำเป็นเท่านั้น

ขอสิทธิ์เมื่อจำเป็นเท่านั้น เช่น

  • อย่าขอสิทธิ์เข้าถึงตำแหน่งเมื่อแอปเริ่มต้นทำงาน เว้นแต่จะจำเป็นอย่างยิ่ง
  • หากแอปกำหนดเป้าหมายเป็น Android 10 ขึ้นไปและมีบริการที่ทำงานอยู่เบื้องหน้า ให้ประกาศ foregroundServiceType ของ "location" ในไฟล์ Manifest
  • อย่าขอสิทธิ์เข้าถึงตำแหน่งในเบื้องหลัง เว้นแต่จะมีกรณีการใช้งานที่ถูกต้องตามที่อธิบายไว้ในการเข้าถึงตำแหน่งของผู้ใช้ที่ปลอดภัยและโปร่งใสยิ่งขึ้น

รองรับการลดระดับอย่างราบรื่นหากไม่ได้รับสิทธิ์

ออกแบบแอปให้รองรับสถานการณ์ต่อไปนี้ได้อย่างราบรื่นเพื่อรักษาประสบการณ์การใช้งานที่ดี

  • แอปของคุณไม่มีสิทธิ์เข้าถึงข้อมูลตำแหน่ง
  • แอปของคุณไม่มีสิทธิ์เข้าถึงข้อมูลตำแหน่งเมื่อทำงานในเบื้องหลัง

8. ขอแสดงความยินดี

คุณได้เรียนรู้วิธีรับข้อมูลอัปเดตตำแหน่งใน Android โดยคำนึงถึงแนวทางปฏิบัติแนะนำแล้ว

ดูข้อมูลเพิ่มเติม