C.d.b -> Неустранимое исключение: android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeExceptionAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 C.d.b -> Неустранимое исключение: android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException

Сообщение Anonymous »

Я постоянно сталкиваюсь с той же ошибкой, что и в Firebase Crashlytics.
Неустрашимое исключение: android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException

Код: Выделить всё

Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{a871ed3 u0 com.package.id/id.flutter.flutter_background_service.BackgroundService c:com.package.id}

Код: Выделить всё

Caused by android.app.StackTrace
Last startServiceCommon() call for this service was made here

android.content.ContextWrapper.startForegroundService (ContextWrapper.java:849)
C.d.b (SourceFile:1)
C.h.startForegroundService (SourceFile:7)
id.flutter.flutter_background_service.FlutterBackgroundServicePlugin.start (알 수 없는 소스:24)
id.flutter.flutter_background_service.FlutterBackgroundServicePlugin.onMethodCall (SourceFile:232)
b3.m.o (SourceFile:21)
a6.c.run (SourceFile:124)
android.os.Handler.handleCallback (Handler.java:959)
Я знаю, что это происходит, когда служба переднего плана не запускается в течение 5 секунд после ее вызова.
Поэтому я запрашиваю службу переднего плана только тогда, когда это возможно, как показано ниже:
MainActivity.kr

Код: Выделить всё

class MainActivity : FlutterActivity() {

// ===== 가드 상태 =====
@Volatile private var startingInProgress = false
private var lastStartAttemptMs = 0L
private val throttleWindowMs = 1200L
private val fgsStartTimeoutMs = 5000L
private val mainHandler = Handler(Looper.getMainLooper())

// “앱 전역” 라이프사이클 (Process 단위) — RESUMED일 때만 ‘진짜 전경’으로 본다
private fun isAppReallyResumed(): Boolean {
return ProcessLifecycleOwner.get().lifecycle.currentState == Lifecycle.State.RESUMED
}

private fun hasPostNotificationsPermission(): Boolean {
if (Build.VERSION.SDK_INT < 33) return true
return ContextCompat.checkSelfPermission(
this,
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
}

private fun hasStepCounterSensor(): Boolean {
val sm = getSystemService(Context.SENSOR_SERVICE) as SensorManager
return sm.getDefaultSensor(Sensor.TYPE_STEP_COUNTER) != null
}

/**
* 전제조건 점검 (전경/권한/센서/중복/쓰로틀)
*/
private fun checkPreconditions(): Pair {
if (!isAppReallyResumed()) return false to "APP_NOT_RESUMED"
if (!hasPostNotificationsPermission()) return false to "NOTIF_PERMISSION_DENIED"
if (!hasStepCounterSensor()) return false to "NO_STEP_SENSOR"
if (StepCountService.isSensorRegistered) return false to "ALREADY_RUNNING"
if (startingInProgress) return false to "ALREADY_STARTING"
val now = SystemClock.elapsedRealtime()
if (now - lastStartAttemptMs < throttleWindowMs) return false to "THROTTLED"
return true to null
}

/**
* RESUMED이 될 때까지 최대 waitMillis 동안 폴링.
* 되면 onResumed 콜백 실행, 아니면 onGiveUp 실행
*/
private fun waitUntilResumed(
waitMillis: Long = 2000L,
interval: Long = 50L,
onResumed: () -> Unit,
onGiveUp: (String) -> Unit
) {
val start = SystemClock.elapsedRealtime()
fun tick() {
if (isAppReallyResumed()) {
onResumed();  return
}
if (SystemClock.elapsedRealtime() - start >= waitMillis) {
onGiveUp("RESUME_TIMEOUT")
return
}
mainHandler.postDelayed({ tick() }, interval)
}
tick()
}

private fun safeStartStepService(result: MethodChannel.Result) {
val (ok, reason) = checkPreconditions()
if (!ok) {
// RESUMED 전이면 잠깐 기다렸다가 다시 체크
if (reason == "APP_NOT_RESUMED") {
waitUntilResumed(
waitMillis = 2000L,
interval = 50L,
onResumed = { safeStartStepService(result) },
onGiveUp = { reason2 ->
result.error("FGS_GUARD_BLOCKED", reason2, null)
}
)
return
}
result.error("FGS_GUARD_BLOCKED", reason ?: "BLOCKED", null)
return
}

try {
startingInProgress = true
lastStartAttemptMs = SystemClock.elapsedRealtime()
// 5초 후에도 서비스가 못 올라오면 시작중 플래그 해제
mainHandler.postDelayed({ startingInProgress = false }, fgsStartTimeoutMs)

val intent = Intent(this, StepCountService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(this, intent)
} else {
startService(intent)
}
result.success(null)
} catch (t: Throwable) {
startingInProgress = false
result.error("FGS_START_FAILED", t.message, null)
}
}

override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)

MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "step_service")
.setMethodCallHandler { call, result ->
when (call.method) {
"startStepService" -> safeStartStepService(result)

"stopStepService" -> {
startingInProgress = false
val intent = Intent(this, StepCountService::class.java)
stopService(intent)
result.success(null)
}

"isSensorActive" -> result.success(StepCountService.isSensorRegistered)

else ->  result.notImplemented()
}
}
}
}
И мой код ForegroundService приведен ниже:

Код: Выделить всё

class StepCountService : Service(), SensorEventListener {

private lateinit var sensorManager: SensorManager
private var stepSensor: Sensor? = null
val notificationId = 1
val channelId = "step_service_channel"
private lateinit var notificationManager:NotificationManager
@Volatile private var started = false

companion object {
var isSensorRegistered: Boolean = false
}

private var becameForeground = false
private val guard = Handler(Looper.getMainLooper())

override fun onCreate() {
super.onCreate()
notificationManager = getSystemService(android.app.Service.NOTIFICATION_SERVICE) as NotificationManager
createChannelIfNeeded()
sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
stepSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)

guard.postDelayed({ if (!becameForeground) stopSelf() }, 4000)

becameForeground = startInForeground()
if(!becameForeground) return
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// 1) 센서가 없으면 종료
if(!becameForeground) {
stopSelf()
return START_NOT_STICKY
}

if(stepSensor == null) {
stopForeground(Service.STOP_FOREGROUND_REMOVE)
stopSelf()
return START_NOT_STICKY
}

if(!isSensorRegistered) {
sensorManager.registerListener(this, stepSensor, SensorManager.SENSOR_DELAY_UI)
isSensorRegistered = true
}
return START_STICKY
}

@SuppressLint("WrongConstant")
private fun startInForeground(): Boolean {
val prefs = this.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE)
val todayStepOffset = prefs.getLong("flutter.${getTodayKey()}_stepCount", 0)
val notification = buildNotification(todayStepOffset)

return  try {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
startForeground(
notificationId,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_HEALTH,
)
} else {
startForeground(notificationId, notification)
}
true
} catch (t: Throwable) {
// 여기서 바로 종료하면 5초 룰 위반으로 번지지 않습니다.
stopSelf()
false
}
}

private fun createChannelIfNeeded() {
val channelName = "걸음수 측정 서비스"

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val chan = NotificationChannel(
channelId,
channelName,
NotificationManager.IMPORTANCE_HIGH
)
notificationManager.createNotificationChannel(chan)
}
}

private fun buildNotification(stepCount: Long): Notification {
return NotificationCompat.Builder(this, channelId)
.setContentText("$stepCount 걸음")
.setSmallIcon(R.drawable.ic_stat_noti_icon)
.setOnlyAlertOnce(true)
.setOngoing(true)
.build()
}

override fun onBind(p0: Intent?): IBinder? {
return null
}

override fun onSensorChanged(event: SensorEvent?) {
event?.let {
val stepCount = it.values[0].toLong()
val prefs = this.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE)
val editor = prefs.edit()
val todayTotalStepPrefsName = "flutter.${getTodayKey()}_totalStepCount"
val todayStepPrefsName = "flutter.${getTodayKey()}_stepCount"
val todayDummyPrefsName = "flutter.${getTodayKey()}_dummy"
var todayStep: Long = 0
var todayDummy:  Long = 0

val isAlreadySet = prefs.getBoolean("flutter.isFirstStepSet", false)
todayDummy = prefs.getLong(todayDummyPrefsName, 0)

if(isAlreadySet) {
todayStep = stepCount - todayDummy
} else {
// 처음 받으면
todayStep = prefs.getLong(todayStepPrefsName, 0)
todayDummy = stepCount - todayStep
editor.putBoolean("flutter.isFirstStepSet", true)
}

if(todayStep < 0 || todayDummy == 0L)  {
todayStep = 0
todayDummy = stepCount
}

editor.putLong(todayTotalStepPrefsName, stepCount)
editor.putLong(todayDummyPrefsName, todayDummy)
editor.putLong(todayStepPrefsName, todayStep)
editor.apply()
//            buildNotification(todayStep)
}
}

override fun onDestroy() {
sensorManager.unregisterListener(this)
isSensorRegistered = false
started = false

if(becameForeground) {
stopForeground(Service.STOP_FOREGROUND_REMOVE)
}
super.onDestroy()
}

private fun getTodayKey(): String {
val formatter = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
return formatter.format(Date())
}

override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
//
}
}
Я переместил код запроса службы переднего плана из onStartCommand в onCreate, чтобы предотвратить эту ошибку.
Но независимо от того, находится ли он в onStartCommand или onCreate, возникает эта ошибка.
Пожалуйста, помогите мне.>

Подробнее здесь: https://stackoverflow.com/questions/797 ... dservicedi
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»