簡體   English   中英

Android - 如何在服務的后台獲取位置更新

[英]Android - How do I get location updates in the background in a service

當我的應用程序運行時,我需要在后台訪問位置。

當我的主要活動實施android.location.LocationListener時,我成功接收到位置更新

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
    val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
    val criteria = Criteria()
    val provider = locationManager.getBestProvider(criteria, false)
    val location = locationManager.getLastKnownLocation(provider)

    locationManager.requestLocationUpdates(provider, 5000, 20f, this)
    setLocation(location)
} else {
    /* ... */
}

However I attempted to add this code to a new service class (implementing both android.app.Service and android.location.LocationListener ), and the onLocationChanged function is only firing when the app is in view.

我相信這個問題可能是以下之一:

  1. 我想我在某處讀到我必須在服務中手動創建一個新線程,以便它不會在與主要活動相同的線程上運行。 這可能是問題所在,但我不知道如何做到這一點。 我是 android 開發和 Kotlin 的新手。

  2. 我想我在某處讀到,在后台訪問位置時,我當前請求的位置權限還不夠,但找不到要更改的內容。

  3. 我在某處看到了一個解決方案,他們創建了一個每隔幾秒運行一次的計時器,並從位置管理器手動請求最后一個位置。 我沒有對此進行測試,但如果它確實有效,它並不能滿足我的需求。 requestLocationUpdates允許我配置最短時間和最短距離。 當然,我可以手動添加距離檢查,但這可能會影響電池壽命和性能。

我該如何解決這個問題?

(如果有人不熟悉 Kotlin,我可以將任何 Java 代碼更改為 Kotlin)


編輯 1

  • 我的服務肯定正在運行,因為在前台接收到位置更新

  • 這是我的服務的onStartCommand代碼:

override fun onStartCommand(intent: Intent, flags: Int, startid: Int): Int {
    /* request location updates as above */
    return START_STICKY
}
  • 以下是我在主要活動中啟動服務的方式:
val serviceIntent = Intent(applicationContext, OnTheFlyLandmarkService::class.java)
startService(serviceIntent)

編輯 2

  1. 我還讀到我需要顯示一條通知,讓用戶知道我的服務正在后台運行。 我嘗試了以下代碼,但這沒有幫助:

     val notification = NotificationCompat.Builder(this, CHANNEL_ID).setSmallIcon(R.drawable.messageicon).setContentTitle("My app").setContentText("Accessing location in background...").setAutoCancel(true).setPriority(NotificationCompat.PRIORITY_DEFAULT).build() with(NotificationManagerCompat.from(this)) { notify(id, notification) }

編輯 3

我嘗試了@Michael 所說的:在服務中調用startForeground並傳入通知。 這不起作用,我什至沒有看到通知。

override fun onStartCommand(intent: Intent, flags: Int, startid: Int): Int {
    val notification = buildNotification("My app", "Accessing location in background...")
    startForeground(NOTIFICATION_ID_SERVICE, notification)

    /* request location updates */
    return START_STICKY
}

對於使用始終運行的Service ,您有一些重要的事情:

  1. 將其添加到您的清單中
    <manifest ... >
      ...
      <application ... >
          <service android:name=".ExampleService" />
          ...
      </application>
    </manifest>
  1. 讓它START_STICKY以便系統重新啟動它,以防它殺死它。
    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show()
        // ...

        // If we get killed, after returning from here, restart
        return START_STICKY
    }
  1. 在前台啟動它,這是針對 Android 9(API 級別 28)的任何應用程序所必需的。 否則你會得到一個SecurityException 加上清單中的權限
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
  1. 要在您的服務和您的活動之間傳遞位置數據,您還可以考慮綁定機制。 (詳見第二個鏈接,請注意示例中的通知創建在沒有通道的情況下已過時

你已經有了 1 和 2。所以你必須做 3。

在您的 Service OnCreate方法中使用前台通知。

val pendingIntent: PendingIntent =
        Intent(this, ExampleActivity::class.java).let { notificationIntent ->
            PendingIntent.getActivity(this, 0, notificationIntent, 0)
        }

val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.messageicon)
.setContentTitle("My app")
.setContentText("Accessing location in background...")
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build()

startForeground(ONGOING_NOTIFICATION_ID, notification)
// Caution: The integer ID that you give to startForeground() must not be 0.

更多細節請查看官方文檔:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM