几个小时后,我的无尽后台服务自动停止。为啥?
Posted
技术标签:
【中文标题】几个小时后,我的无尽后台服务自动停止。为啥?【英文标题】:My Endless background Service Stopped Automatically After Few Hours . Why?几个小时后,我的无尽后台服务自动停止。为什么? 【发布时间】:2021-07-16 17:21:54 【问题描述】:我没完没了的前台服务在 3 到 4 小时后自动停止,没有出现任何问题吗? LatLong 在服务器中连续保存了 3 - 4 个小时,但服务随机关闭或销毁,我不知道如何处理这个问题?
class MyEndlessService : Service() , DatabaseListenerCallback
private var wakeLock: PowerManager.WakeLock? = null
private var isServiceStarted = false
var TAG = "MyService"
var gps_status = 1
var editor: SharedPreferences.Editor? = null
var previousBestLocation: Location? = null
var apiInterface: GetDataService? = null
private var googleApiClient: GoogleApiClient? = null
private var lastLocation: Location? = null
private var locationRequest: LocationRequest? = null
private val UPDATE_INTERVAL = 10000
private val FASTEST_INTERVAL = UPDATE_INTERVAL / 2
var locationManager: LocationManager? = null
var isFirsttime = true
var sharedPreferences: SharedPreferences? = null
override fun onBind(intent: Intent): IBinder?
return null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int
log("onStartCommand executed with startId: $startId")
if (intent != null)
val action = intent.action
log("using an intent with action $action")
when (action)
Actions.START.name -> startService()
Actions.STOP.name -> stopService()
else -> log("This should never happen. No action in the received intent")
else
log(
"with a null intent. It has been probably restarted by the system."
)
return START_STICKY
override fun onCreate()
super.onCreate()
log("The service has been created".toUpperCase())
val notification = createNotification()
startForeground(1, notification)
override fun onDestroy()
super.onDestroy()
log("The service has been destroyed".toUpperCase())
val calendar = Calendar.getInstance()
val mdformat = SimpleDateFormat("HH:mm:ss")
val strDate = mdformat.format(calendar.time)
LocalDatabaseForException(applicationContext,strDate,"Service Destroyed").execute()
val broadcastIntent = Intent()
broadcastIntent.action = "restartservice"
broadcastIntent.setClass(this, Restarter::class.java)
this.sendBroadcast(broadcastIntent)
override fun onTaskRemoved(rootIntent: Intent)
val restartServiceIntent = Intent(applicationContext, MyEndlessService::class.java).also
it.setPackage(packageName)
;
val restartServicePendingIntent: PendingIntent = PendingIntent.getService(
this,
1,
restartServiceIntent,
PendingIntent.FLAG_ONE_SHOT
);
applicationContext.getSystemService(Context.ALARM_SERVICE);
val alarmService: AlarmManager = applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager;
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent
);
private fun startService()
val calendar = Calendar.getInstance()
val mdformat = SimpleDateFormat("HH:mm:ss")
val strDate = mdformat.format(calendar.time)
LocalDatabaseForException(applicationContext,strDate,"Service Started").execute()
if (isServiceStarted) return
log("Starting the foreground service task")
// Toast.makeText(this, "Service starting its task", Toast.LENGTH_SHORT).show()
isServiceStarted = true
setServiceState(this, ServiceState.STARTED)
// we need this lock so our service gets not affected by Doze Mode
wake lock =
(getSystemService(Context.POWER_SERVICE) as PowerManager).run
newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "EndlessService::lock").apply
acquire()
// we're starting a loop in a coroutine
GlobalScope.launch(Dispatchers.IO)
while (isServiceStarted)
launch(Dispatchers.IO)
pingFakeServer()
handleUserTracking()
delay(1000)
log("End of the loop for the service")
private fun stopService()
log("Stopping the foreground service")
// Toast.makeText(this, "Service stopping", Toast.LENGTH_SHORT).show()
val calendar = Calendar.getInstance()
val mdformat = SimpleDateFormat("HH:mm:ss")
val strDate = mdformat.format(calendar.time)
LocalDatabaseForException(applicationContext,strDate,"Service Stopped").execute()
try
wakeLock?.let
if (it.isHeld)
// startService()
it.release()
// stopForeground(true)
// stopSelf()
catch (e: Exception)
log("Service stopped without being started: $e.message")
val calendar = Calendar.getInstance()
val mdformat = SimpleDateFormat("HH:mm:ss")
val strDate = mdformat.format(calendar.time)
LocalDatabaseForException(applicationContext,strDate,"Service stopped without being started: $e.message").execute()
isServiceStarted = false
setServiceState(this, ServiceState.STARTED)
private fun pingFakeServer()
SmartLocation.with(applicationContext).location()
.start(object : OnLocationUpdatedListener
override fun onLocationUpdated(location: Location?)
val sharedPreferences = applicationContext.getSharedPreferences(
"AcessToken",
AppCompatActivity.MODE_MULTI_PROCESS
)
editor = getSharedPreferences("AcessToken", MODE_PRIVATE).edit()
editor = getSharedPreferences("AcessToken", MODE_PRIVATE).edit()
editor!!.putString("temp_lattitude", location!!.getLatitude().toString())
editor!!.putString("temp_lattitude", location!!.getLatitude().toString())
editor!!.apply()
val att = sharedPreferences!!.getString("Attendance_ID", "")
val userid = sharedPreferences.getInt("User_ID", 0).toString()
if ((att != "") and (userid != ""))
if (previousBestLocation != null)
if (isBetterLocation(location, previousBestLocation))
previousBestLocation = location
onNewLocationAgainwithLocalDatabase(location)
else
previousBestLocation = location
onNewLocationAgainwithLocalDatabase(location)
)
fun getBatteryPercentage(context: Context): Int
return if (Build.VERSION.SDK_INT >= 21)
val bm = context.getSystemService(BATTERY_SERVICE) as BatteryManager
bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
else
val iFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
val batteryStatus = context.registerReceiver(null, iFilter)
val level = batteryStatus?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1
val scale = batteryStatus?.getIntExtra(BatteryManager.EXTRA_SCALE, -1) ?: -1
val batteryPct = level / scale.toDouble()
(batteryPct * 100).toInt()
fun handleUserTracking()
val settings = applicationContext.getSharedPreferences("AcessToken", MODE_PRIVATE)
val manager = getSystemService(LOCATION_SERVICE) as LocationManager
gps_status = 1
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER))
gps_status = 0
editor = getSharedPreferences("AcessToken", MODE_PRIVATE).edit()
editor!!.putString("temp_lattitude", "")
editor!!.putString("temp_longitude", "")
editor!!.apply()
Log.d("Gps status ", gps_status.toString())
fun hitApitoUpdate(gpsstatus: Int?)
val settings = applicationContext.getSharedPreferences("AcessToken", MODE_PRIVATE)
val lattitude = settings.getString("temp_lattitude", "")
val longitude = settings.getString("temp_longitude", "")
val userID = settings.getInt("User_ID", 0).toString()
val access_token = settings.getString("Access_Token", "")
val battery_per = getBatteryPercentage(this)
apiInterface = APIClient.getClient().create(GetDataService::class.java)
val call = apiInterface!!.updateGpsStatus(
"Bearer $access_token",
gpsstatus,
userID,
lattitude,
longitude,
battery_per
)
call.enqueue(object : Callback<GpaStatusPojo>
override fun onResponse(call: Call<GpaStatusPojo>, response: Response<GpaStatusPojo>)
try
// Toast.makeText(applicationContext,""+response.body()!!.message,Toast.LENGTH_SHORT).show()
Log.d("Gps status ", response.body()!!.message)
catch (e: java.lang.Exception)
val dfgdsdsdsfds = ""
Log.d("Gps sttaus 22 :", e.toString())
override fun onFailure(call: Call<GpaStatusPojo>, t: Throwable)
Log.d("Gps sttaus 33 :", t.toString())
)
private fun onNewLocationAgainwithLocalDatabase(location: Location)
val calendar = Calendar.getInstance()
val mdformat = SimpleDateFormat("HH:mm:ss")
val strDate = mdformat.format(calendar.time)
LocalDatabaseInsert(location, strDate, applicationContext).execute()
InsertLocationData(location, false, strDate, applicationContext).execute()
getLocationList()
private fun getLocationList()
GetLocationData(applicationContext, this).execute()
override fun processData(locationData: MutableList<LocationParam>?)
hitApitoBulkEnter(locationData!!)
private fun hitApitoBulkEnter(location: List<LocationParam>)
if (!Utils.isNetworkConnected(this))
Toast.makeText(
this,
"No internet connection available. Please check your internet connection.",
Toast.LENGTH_SHORT
).show()
startActivity(Intent(this, InternetSettingCheck::class.java))
return
// send location to the server
private fun readWebPageBulkTest(location: String, mTemp: List<LocationParam>)
if (!Utils.isNetworkConnected(this))
Toast.makeText(
this,
"No internet connection available. Please check your internet connection.",
Toast.LENGTH_SHORT
).show()
startActivity(Intent(this, InternetSettingCheck::class.java))
return
val settings = applicationContext.getSharedPreferences("AcessToken", MODE_PRIVATE)
val access_token = settings.getString("Access_Token", "")
val user_id = settings.getInt("User_ID", 0).toString()
var attendance_id = settings.getString("Attendance_ID", "")
apiInterface = APIClient.getClient().create(GetDataService::class.java)
if (attendance_id == "")
attendance_id = "0"
if (user_id != "")
val call: Call<NewLocationPojo> = apiInterface!!.updateLatLongforUserIDBulk(
"Bearer $access_token",
location
)
Log.e("JsonLocation :", location)
call.enqueue(object : Callback<NewLocationPojo>
override fun onResponse(
call: Call<NewLocationPojo>,
response: Response<NewLocationPojo>
)
try
if (response.body()!!.status == "success")
Log.e("Api response :", response.body()!!.status)
Toast.makeText(
this@MyEndlessService,
"" + response.body()!!.status.toString(),
Toast.LENGTH_SHORT
).show()
updatelatlong(location, mTemp)
else
Toast.makeText(
this@MyEndlessService,
"" + response.body()!!.status.toString(),
Toast.LENGTH_SHORT
).show()
catch (e: java.lang.Exception)
Toast.makeText(this@MyEndlessService, "" + e.toString(), Toast.LENGTH_SHORT)
.show()
Log.e("ServerSam :", e.toString())
override fun onFailure(call: Call<NewLocationPojo>, t: Throwable)
Log.e("ServerSam :", t.toString())
log("The service has been destroyed".toUpperCase())
val calendar = Calendar.getInstance()
val mdformat = SimpleDateFormat("HH:mm:ss")
val strDate = mdformat.format(calendar.time)
LocalDatabaseForException(applicationContext,strDate,"Api Error :"+t.toString() ).execute()
)
private fun getPostFinal()
class GetTasks : AsyncTask<Void?, Void?, List<LocationParam>>()
override fun onPostExecute(tasks: List<LocationParam>)
super.onPostExecute(tasks)
DeleteLocationData(applicationContext).execute()
GetLocationData22().execute()
// testDataAfterDeleteion();
override fun doInBackground(vararg params: Void?): List<LocationParam>
val taskList = DatabaseClient
.getInstance(applicationContext)
.appDatabase
.locationDao()
.all
Log.e("Database after updation", taskList.toString())
return taskList
val gt = GetTasks()
gt.execute()
internal class GetLocationData22 : AsyncTask<Void?, Void?, List<LocationParam>>()
var mContext: Context? = null
override fun onPostExecute(tasks: List<LocationParam>)
super.onPostExecute(tasks)
override fun doInBackground(vararg params: Void?): List<LocationParam>
val taskList = DatabaseClient.getInstance(mContext)
.appDatabase
.locationDao()
.all
Log.d("GetAfterDeleteion :", taskList.toString())
return taskList
protected fun isBetterLocation(location: Location, currentBestLocation: Location?): Boolean
if (currentBestLocation == null)
// A new location is always better than no location
return true
// Check whether the new location fix is newer or older
val timeDelta = location.time - currentBestLocation.time
val isSignificantlyNewer = timeDelta > MyService66.TWO_MINUTES
val isSignificantlyOlder = timeDelta < -MyService66.TWO_MINUTES
val isNewer = timeDelta > 0
// If it's been more than two minutes since the current location, use the new location
// because the user has likely moved
if (isSignificantlyNewer)
return true
// If the new location is more than two minutes older, it must be worse
else if (isSignificantlyOlder)
return false
// Check whether the new location fix is more or less accurate
val accuracyDelta = (location.accuracy - currentBestLocation.accuracy).toInt()
val isLessAccurate = accuracyDelta > 0
val isMoreAccurate = accuracyDelta < 0
val isSignificantlyLessAccurate = accuracyDelta > 200
// Check if the old and new location are from the same provider
val isFromSameProvider: Boolean =
isSameProvider(location.provider, currentBestLocation.provider)
// Determine location quality using a combination of timeliness and accuracy
if (isMoreAccurate)
return true
else if (isNewer && !isLessAccurate)
return true
else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider)
return true
return false
/**
* Checks whether two providers are the same
*/
private fun isSameProvider(provider1: String?, provider2: String?): Boolean
return if (provider1 == null)
provider2 == null
else provider1 == provider2
private fun createNotification(): Notification
val notificationChannelId = "ENDLESS SERVICE CHANNEL"
// depending on the android API that we're dealing with we will have
// to use a specific method to create the notification
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channel = NotificationChannel(
notificationChannelId,
"Endless Service notifications channel",
NotificationManager.IMPORTANCE_HIGH
).let
it.description = "Endless Service channel"
it.enableLights(true)
it.lightColor = Color.RED
it.enableVibration(true)
it.vibrationPattern = longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400)
it
notificationManager.createNotificationChannel(channel)
val pendingIntent: PendingIntent = Intent(this, MainActivityFinal2::class.java).let notificationIntent ->
PendingIntent.getActivity(this, 0, notificationIntent, 0)
val builder: Notification.Builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) Notification.Builder(
this,
notificationChannelId
) else Notification.Builder(this)
return builder
.setContentTitle("Sapphire location on")
// .setContentText("This is your favorite endless service working")
.setContentIntent(pendingIntent)
.setSmallIcon(R.mipmap.app_icon)
// .setTicker("Ticker text")
.setPriority(Notification.PRIORITY_HIGH) // for under android 26 compatibility
.build()
【问题讨论】:
请更具体。如果您创建了一个重现您的问题的小示例,将会有所帮助。你的班级很大,很难理解究竟是什么导致了这个问题。 【参考方案1】:服务可以停止,并且很可能会在某个时候被操作系统停止。根据文档
Android 系统仅在内存不足时才会停止服务,并且必须为具有用户焦点的 Activity 恢复系统资源。如果服务绑定到具有用户焦点的活动,则它被杀死的可能性较小;如果服务被声明在前台运行,它很少被杀死。如果服务已启动并长时间运行,系统会随着时间的推移降低其在后台任务列表中的位置,并且该服务变得非常容易被杀死——如果您的服务已启动,您必须将其设计为优雅地处理由系统。如果系统终止了您的服务,它会在资源可用时立即重新启动它,但这也取决于您从 onStartCommand() 返回的值。
重启服务最好的办法就是在onStartCommand()
中声明服务为STICKY_SERVICE
【讨论】:
以上是关于几个小时后,我的无尽后台服务自动停止。为啥?的主要内容,如果未能解决你的问题,请参考以下文章