如何解决我无尽的后台服务在几个小时后自动停止为什么?
我的无限前台服务在 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,"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
wakeLock =
(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,"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,"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,applicationContext).execute()
InsertLocationData(location,false,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,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,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,"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?,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)
it
}
notificationmanager.createNotificationChannel(channel)
}
val pendingIntent: PendingIntent = Intent(this,MainActivityFinal2::class.java).let { notificationIntent ->
PendingIntent.getActivity(this,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()
}
}
解决方法
服务可以被停止,并且很可能在某个时候被操作系统停止。根据文档
Android 系统仅在内存不足时停止服务,并且必须为用户关注的 Activity 恢复系统资源。如果服务绑定到一个以用户为焦点的活动,那么它被杀死的可能性就较小;如果服务被声明为在前台运行,它很少被杀死。如果服务启动并长时间运行,系统会随着时间的推移降低其在后台任务列表中的位置,并且服务变得非常容易被杀死——如果您的服务已启动,您必须将其设计为优雅地处理重启系统。如果系统终止了您的服务,它会在资源可用时立即重新启动它,但这也取决于您从 onStartCommand() 返回的值。
重新启动服务的最佳做法是将服务声明为 STICKY_SERVICE
中的 onStartCommand()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。