ForegroundService不能在后台工作,这取决于设备



我想在Android设备中使用Kotlin计算应用程序关闭或在后台运行时的步数。

所以我使用Servicenotification像下面这样24/7运行。

onCreateonStartonStartCommand中,我注册sensorManager来计算步骤和呼叫通知,以便在后台运行它,应用程序关闭。

step在onSensorChanged中计数

我的服务代码如下,请仔细查看。

class MyService : Service(), SensorEventListener {
private val db = Firebase.firestore
private val userDB = Firebase.firestore.collection("users")
private val diaryDB = Firebase.firestore.collection("diary")
private val userId = Firebase.auth.currentUser?.uid
private var todayStepCountFromDB = 0
//    lateinit var diaryUpdateBroadcastReceiver: DiaryUpdateBroadcastReceiver
lateinit var dateChangeBroadcastReceiver: DateChangeBroadcastReceiver
lateinit var deviceShutdownBroadcastReceiver: DeviceShutdownBroadcastReceiver
lateinit var stepCountBroadcastReceiver: StepCountBroadcastReceiver
companion object {
lateinit var sensorManager: SensorManager
lateinit var step_sensor: Sensor
const val ACTION_STEP_COUNTER_NOTIFICATION =
"com.chungchunon.chunchunon_android.STEP_COUNTER_NOTIFICATION"
var todayTotalStepCount: Int? = 0
const val STEP_THRESHOLD: Double = 6.5
const val stepCountSharedPref = "stepCountSharedPreference"
const val dateChangeSharedPref = "dateChangeSharedPref"
}
lateinit var prefs: SharedPreferences
private var startingStepCount: Int = 0
private var stepCount: Int = 0

override fun onCreate() {
super.onCreate()
StepCountNotification(this, todayTotalStepCount)
// 기본
sensorManager =
applicationContext?.getSystemService(Context.SENSOR_SERVICE) as SensorManager
step_sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)
sensorManager.registerListener(this, step_sensor, SensorManager.SENSOR_DELAY_FASTEST)
// 오늘 걸음수 초기화
userDB.document("$userId").get().addOnSuccessListener { document ->
var todayStepCountFromDB = document.getLong("todayStepCount") ?: 0
todayTotalStepCount = todayStepCountFromDB.toInt()
StepCountNotification(this, todayTotalStepCount)
}
// shared preference 설정
prefs = getSharedPreferences(stepCountSharedPref, Context.MODE_PRIVATE)
var dummyData = prefs.getInt(userId, 0)
var datePrefs = getSharedPreferences(dateChangeSharedPref, Context.MODE_PRIVATE)
// DateChangeBroadcastReceiver : 매일 걸음수 0
dateChangeBroadcastReceiver = DateChangeBroadcastReceiver()
val dateChangeIntent = IntentFilter()
dateChangeIntent.addAction(Intent.ACTION_TIME_TICK)
applicationContext?.registerReceiver(dateChangeBroadcastReceiver, dateChangeIntent)
// DeviceShutDownBroadcastReceiver : 핸드폰 꺼질 때
deviceShutdownBroadcastReceiver = DeviceShutdownBroadcastReceiver()
val deviceShutdownIntent = IntentFilter()
deviceShutdownIntent.addAction(Intent.ACTION_SHUTDOWN)
applicationContext?.registerReceiver(deviceShutdownBroadcastReceiver, deviceShutdownIntent)
// StepCountBroadcastReceiver : 디비 저장
stepCountBroadcastReceiver = StepCountBroadcastReceiver()

LocalBroadcastManager.getInstance(applicationContext).registerReceiver(
stepInitializeReceiver,
IntentFilter("NEW_DATE_STEP_ZERO")
);
}
override fun onBind(p0: Intent?): IBinder? {
return null
}
override fun onSensorChanged(sensorEvent: SensorEvent?) {
startingStepCount = prefs.getInt(userId, 0)
stepCount = sensorEvent!!.values[0].toInt()
val editor = prefs.edit()
db.collection("user_step_count").document("$userId")
.get()
.addOnSuccessListener { document ->
if (document.exists()) {
var snapShot = document.data
var dateFormat = SimpleDateFormat("yyyy-MM-dd")
var cal = Calendar.getInstance()
cal.add(Calendar.DATE, -1)
var yesterday = dateFormat.format(cal.getTime())
if (snapShot!!.containsKey("dummy") && snapShot!!.containsKey(yesterday)) {
// 더미값 존재
var dummyStepCount = (snapShot["dummy"] as Long).toInt()
todayTotalStepCount = stepCount - dummyStepCount
var intentToFirebase = Intent(this, StepCountBroadcastReceiver::class.java)
intentToFirebase.setAction(ACTION_STEP_COUNTER_NOTIFICATION)
intentToFirebase.putExtra("todayTotalStepCount", todayTotalStepCount)
sendBroadcast(intentToFirebase)
StepCountNotification(this, todayTotalStepCount)

var intentToMyDiary = Intent(ACTION_STEP_COUNTER_NOTIFICATION).apply {
putExtra(
"todayTotalStepCount",
todayTotalStepCount
)
}
LocalBroadcastManager.getInstance(applicationContext!!)
.sendBroadcast(intentToMyDiary)

Log.d(
"걸음수 체크체크 2",
"stepCount: ${stepCount} // startingStepCount: ${dummyStepCount}"
)
} else {
// 더미값 존재 x
var newDummySet = hashMapOf(
"dummy" to stepCount
)
db.collection("user_step_count").document("$userId")
.set(newDummySet, SetOptions.merge())
StepCountNotification(this, 0)
var intentToFirebase = Intent(this, StepCountBroadcastReceiver::class.java)
intentToFirebase.setAction(ACTION_STEP_COUNTER_NOTIFICATION)
intentToFirebase.putExtra("todayTotalStepCount", 0)
sendBroadcast(intentToFirebase)
var intentToMyDiary = Intent(ACTION_STEP_COUNTER_NOTIFICATION).apply {
putExtra(
"todayTotalStepCount",
0
)
}
LocalBroadcastManager.getInstance(applicationContext!!)
.sendBroadcast(intentToMyDiary)
}
}
}
}
override fun onAccuracyChanged(p0: Sensor?, p1: Int) {
Log.d("서비스", "accuracychanged")
}
override fun onStart(intent: Intent?, startId: Int) {
super.onStart(intent, startId)
sensorManager.registerListener(this, step_sensor, SensorManager.SENSOR_DELAY_FASTEST)
StepCountNotification(this, todayTotalStepCount)
// 기본
sensorManager =
applicationContext?.getSystemService(Context.SENSOR_SERVICE) as SensorManager
step_sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)
sensorManager.registerListener(this, step_sensor, SensorManager.SENSOR_DELAY_FASTEST)
// 오늘 걸음수 초기화
userDB.document("$userId").get().addOnSuccessListener { document ->
var todayStepCountFromDB = document.getLong("todayStepCount") ?: 0
todayTotalStepCount = todayStepCountFromDB.toInt()
StepCountNotification(this, todayTotalStepCount)
}
// DateChangeBroadcastReceiver : 매일 걸음수 0
dateChangeBroadcastReceiver = DateChangeBroadcastReceiver()
val dateChangeIntent = IntentFilter()
dateChangeIntent.addAction(Intent.ACTION_TIME_TICK)
applicationContext?.registerReceiver(dateChangeBroadcastReceiver, dateChangeIntent)
// DeviceShutDownBroadcastReceiver : 핸드폰 꺼질 때
deviceShutdownBroadcastReceiver = DeviceShutdownBroadcastReceiver()
val deviceShutdownIntent = IntentFilter()
deviceShutdownIntent.addAction(Intent.ACTION_SHUTDOWN)
applicationContext?.registerReceiver(deviceShutdownBroadcastReceiver, deviceShutdownIntent)
// StepCountBroadcastReceiver : 디비 저장
stepCountBroadcastReceiver = StepCountBroadcastReceiver()
LocalBroadcastManager.getInstance(applicationContext).registerReceiver(
stepInitializeReceiver,
IntentFilter("NEW_DATE_STEP_ZERO")
);
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
sensorManager.registerListener(this, step_sensor, SensorManager.SENSOR_DELAY_FASTEST)
StepCountNotification(this, todayTotalStepCount)
// 기본
sensorManager =
applicationContext?.getSystemService(Context.SENSOR_SERVICE) as SensorManager
step_sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)
sensorManager.registerListener(this, step_sensor, SensorManager.SENSOR_DELAY_FASTEST)
// 오늘 걸음수 초기화
userDB.document("$userId").get().addOnSuccessListener { document ->
var todayStepCountFromDB = document.getLong("todayStepCount") ?: 0
todayTotalStepCount = todayStepCountFromDB.toInt()
StepCountNotification(this, todayTotalStepCount)
}
// DateChangeBroadcastReceiver : 매일 걸음수 0
dateChangeBroadcastReceiver = DateChangeBroadcastReceiver()
val dateChangeIntent = IntentFilter()
dateChangeIntent.addAction(Intent.ACTION_TIME_TICK)
applicationContext?.registerReceiver(dateChangeBroadcastReceiver, dateChangeIntent)
// DeviceShutDownBroadcastReceiver : 핸드폰 꺼질 때
deviceShutdownBroadcastReceiver = DeviceShutdownBroadcastReceiver()
val deviceShutdownIntent = IntentFilter()
deviceShutdownIntent.addAction(Intent.ACTION_SHUTDOWN)
applicationContext?.registerReceiver(deviceShutdownBroadcastReceiver, deviceShutdownIntent)
// StepCountBroadcastReceiver : 디비 저장
stepCountBroadcastReceiver = StepCountBroadcastReceiver()
LocalBroadcastManager.getInstance(applicationContext).registerReceiver(
stepInitializeReceiver,
IntentFilter("NEW_DATE_STEP_ZERO")
);
return START_STICKY
}

var stepInitializeReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
StepCountNotification(context!!, 0)
}
}
private fun StepCountNotification(context: Context, stepCount: Int?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val CHANNEL_ID = "my_app"
val channel = NotificationChannel(
CHANNEL_ID,
"MyApp", NotificationManager.IMPORTANCE_LOW
)
(context.getSystemService(Service.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(
channel
)
var decimal = DecimalFormat("#,###")
var step = decimal.format(stepCount)
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_new_alarm_icon)
.setContentTitle("$step 걸음")
.setDefaults(Notification.DEFAULT_LIGHTS)
.setOngoing(true)
.setShowWhen(false)
.build()
startForeground(1, notification)
}
}

}

DateChangeBroadcastReceiver的情况下,我创建广播接收器,在新日期00:00时将步长计数重置为0。

在检查ACTIVITY_RECOGNITION权限后,我在Activity中调用它:

userDB.document("$userId").get()
.addOnSuccessListener { document ->
var userType = document.data?.getValue("userType").toString()
if (userType != "파트너") {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACTIVITY_RECOGNITION,
) == PackageManager.PERMISSION_DENIED
) {
//ask for permission
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACTIVITY_RECOGNITION),
100
)
} else {
var startService = Intent(this, MyService::class.java)
//오레오 이상부터 동작하는 코드
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(startService);
} else {
startService(startService);
}
}
}
}

所以我在4个android设备上安装了这个应用程序。

其中三个工作良好,当我关闭应用程序或应用程序进入后台时,步骤计数良好,通知显示在设备上。

但有一台设备在正常工作一段时间后就停止了。

1-2天是完美的,但几天后,计数停止。

我不知道为什么这不起作用,因为我搜索如何使应用程序在后台工作所有在谷歌和堆栈溢出,并应用到我的代码。

这个问题我已经纠结了将近2个月了。

我真的需要你的帮助,只是一些建议或猜测也很有帮助。

如果你需要更多的信息,我可以实时添加。

请帮帮我!

前台服务不会永远存在。他们不是故意的。你说它可以工作1-2天,老实说,这比我预期的要长。如果你想要某些东西在后台持续运行而不被杀死——你不会想要Android作为你的操作系统。这是不允许的。或者至少,你需要一个定制版本的Android。

Android不允许服务无限运行。如果应用程序关闭,服务将被杀死。

你可以试试这些,但没有一个是合适的解决方案

  1. 注册不同的广播接收器,当intent接收到服务时,如果服务不工作,启动服务。
  2. 另一个解决方案是创建一个可以运行并计算步数的小部件。小部件不需要一个应用程序一直运行,但小部件需要由用户放置在用户手机的开始屏幕上,以便小部件开始工作

相关内容