如何解决Android 手机旋转时我的前台服务的多个实例
我正在编写 Android 位置应用和前台服务。该应用程序会定期从服务中获取位置更新。我正在使用 Android Studio 并在 Kotlin 中编写应用程序。
问题在于,当手机旋转时,会创建一个新的前台服务实例。这通过显示位置更新计数以及服务哈希码的日志输出进行了演示:
MainActivity.onCreate(Buddle)
MainActivity.onStart
MainActivity.onResume
>>>>>>>>>>>>>>>>>>> LocationService: onStartCommand
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 1 Service Hash Code: 185408788 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 2 Service Hash Code: 185408788 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 3 Service Hash Code: 185408788 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 4 Service Hash Code: 185408788 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 5 Service Hash Code: 185408788 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 6 Service Hash Code: 185408788 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 7 Service Hash Code: 185408788 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
MainActivity.onPause
MainActivity.onStop
MainActivity.onSaveInstanceState
MainActivity.onCreate(Buddle)
MainActivity.onStart
MainActivity: ======= Location Changed =======
MainActivity.onResume
LocationService: onDestroy ========================================================
>>>>>>>>>>>>>>>>>>> LocationService: onStartCommand
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 8 Service Hash Code: 185408788 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 1 Service Hash Code: 233645514 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 9 Service Hash Code: 185408788 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 2 Service Hash Code: 233645514 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 10 Service Hash Code: 185408788 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 3 Service Hash Code: 233645514 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 11 Service Hash Code: 185408788 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 4 Service Hash Code: 233645514 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 12 Service Hash Code: 185408788 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
LocationService: ******* onLocation Change ******* - Count: 5 Service Hash Code: 233645514 <<<<<<<<<<<<<<
MainActivity: ======= Location Changed =======
手机轮换发生在生命周期活动发生的中途。我一直在研究这个问题,并在过去两天在线搜索寻求帮助,但我看到的与此问题相关的唯一答案是,“您无法创建服务的多个实例”但是日志 似乎 证明不然。我一直不愿意在堆栈溢出上提问,因为我是新手,不完全知道提问的正确方法,但我不知道还能尝试什么。 如果我忘记在我的问题中包含某些内容,请告诉我,谢谢。
主要:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.considerateapps.logger">
<!-- To request foreground location access,declare one of these permissions. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<application
android:allowBackup="true"
android:fullBackupContent="true"
android:hasFragileUserData="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Logger">
<service
android:name=".ui.main.LocationService"
android:foregroundServiceType="location"
android:exported="false"
android:stopWithTask="true"
/>
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyBybVSRyyvJbnHUfYRRi3PJEsodusgKX78" />
<activity
android:name=".MainActivity"
android:label="Logger"
android:theme="@style/Theme.Logger.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
主要活动:
package com.considerateapps.logger
import android.Manifest
import android.content.pm.PackageManager
import android.media.MediaPlayer
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.observe
import com.considerateapps.logger.ui.main.*
class MainActivity : AppCompatActivity()
{
public val TAG = "Logger"
private val locationPermissionCode = 2
override fun onCreate(savedInstanceState: Bundle?)
{
Log.i(TAG,"MainActivity.onCreate(Buddle)")
checkLocationPermission()
startForegroundService()
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
setSupportActionBar(findViewById(R.id.toolbar))
setupObservers()
}
private fun setupObservers()
{
LocationService.location.observe(this as LifecycleOwner)
{
Log.i(TAG,"MainFragment: ======= database Updated Observer ======= ")
val mediaPlayerButtonSound: MediaPlayer = MediaPlayer.create(this,R.raw.ding)
mediaPlayerButtonSound.start()
}
}
private fun checkLocationPermission()
{
if ((ContextCompat.checkSelfPermission(
application,Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED)
) {
ActivityCompat.requestPermissions(
this,arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),locationPermissionCode
)
}
}
private fun startForegroundService()
{
LocationService.startService(this,"Foreground Service is running...")
}
override fun onStart()
{
Log.i(TAG,"MainActivity.onStart")
super.onStart()
}
override fun onResume()
{
Log.i(TAG,"MainActivity.onResume")
super.onResume()
}
override fun onPause()
{
Log.i(TAG,"MainActivity.onPause")
super.onPause()
}
override fun onStop()
{
Log.i(TAG,"MainActivity.onStop")
super.onStop()
}
override fun onSaveInstanceState(outState: Bundle)
{
Log.i(TAG,"MainActivity.onSaveInstanceState")
super.onSaveInstanceState(outState)
}
override fun onLowMemory()
{
Log.i(TAG,"$localClassName.onLowMemory")
super.onLowMemory()
}
override fun onDestroy()
{
LocationService.stopService(this)
super.onDestroy()
}
}
LocationService.kt:
package com.considerateapps.logger.ui.main
import android.Manifest
import android.app.*
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.MutableLiveData
import com.considerateapps.logger.MainActivity
import com.considerateapps.logger.R
class LocationService : Service(),LocationListener
{
val TAG = "Logger"
val NOTIF_ID = 1
private lateinit var locationManager: LocationManager
private var locationUpdateCount = 0
private val CHANNEL_ID = "ForegroundService Kotlin"
companion object
{
val location:MutableLiveData<Location> = MutableLiveData<Location>()
fun startService(context: Context,message: String)
{
val startIntent = Intent(context,LocationService::class.java)
startIntent.putExtra("inputExtra",message)
ContextCompat.startForegroundService(context,startIntent)
}
fun stopService(context: Context)
{
val stopIntent = Intent(context,LocationService::class.java)
context.stopService(stopIntent)
}
}
override fun onStartCommand(intent: Intent?,flags: Int,startId: Int): Int
{
Log.i(TAG,">>>>>>>>>>>>>>>>>>> LocationService: onStartCommand")
locationManager = application.getSystemService(Context.LOCATION_SERVICE) as LocationManager
//do heavy work on a background thread
val input = intent?.getStringExtra("inputExtra")
createNotificationChannel()
val notification = getNotification(input!!)
startForeground(NOTIF_ID,notification)
requestLocationUpdates()
super.onStartCommand(intent,flags,startId)
return START_STICKY
}
private fun getNotification(contentText: String):Notification
{
val notificationIntent = Intent(this,MainActivity::class.java)
notificationIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
val pendingIntent = PendingIntent.getActivity(
this,notificationIntent,PendingIntent.FLAG_UPDATE_CURRENT
)
val notification = NotificationCompat.Builder(this,CHANNEL_ID)
.setOngoing(false)
.setAutoCancel(false)
.setContentTitle("Location Service")
.setContentText(contentText)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentIntent(pendingIntent)
.setOnlyAlertOnce(true)
.build()
return notification
}
private fun updateNotification(contentText: String)
{
val notification: Notification = getNotification(contentText)
val mNotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
mNotificationManager.notify(NOTIF_ID,notification)
}
override fun onBind(intent: Intent): IBinder?
{
return null
}
private fun createNotificationChannel() {
val serviceChannel = NotificationChannel(CHANNEL_ID,"Foreground Service Channel",NotificationManager.IMPORTANCE_DEFAULT)
val manager = getSystemService(NotificationManager::class.java)
manager!!.createNotificationChannel(serviceChannel)
}
private fun requestLocationUpdates()
{
if((ContextCompat.checkSelfPermission(application,Manifest.permission.ACCESS_FINE_LOCATION)) ==PackageManager.PERMISSION_GRANTED)
{
location.value = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,200,0f,this)
}
}
override fun onLocationChanged(i_location: Location) {
locationUpdateCount++
Log.i(TAG,"LocationService: ******* onLocation Change ******* - Count: $locationUpdateCount Service Hash Code: ${hashCode()} <<<<<<<<<<<<<<")
// Toast.makeText(this,"Count:$locationUpdateCount",Toast.LENGTH_SHORT).show();
updateNotification("Count: $locationUpdateCount")
location.value = i_location
}
override fun onDestroy()
{
Log.i(TAG,"LocationService: onDestroy ========================================================")
super.onDestroy()
}
}
解决方法
经过几个小时的调试,我发现了问题:
在 MainActivity.onDestroy() 中,我试图停止我的服务 LocationService。问题是我将位置回调附加到服务,因此当手机旋转时服务泄漏,因为调用 MainActivity.onDestroy() 试图停止服务但显然不能因为附加的位置侦听器和 Android似乎假设它成功停止了服务,因此在下次创建它的新实例。
*** 似乎是 Android 操作系统的错误 ***
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。