Android 9 (круговая диаграмма), Context.startForegroundService () не вызывал Service.startForeground (): ServiceRecord - PullRequest
7 голосов
/ 29 апреля 2019

Прежде всего, я посмотрел на них;

enter image description here

У меня есть потоковое приложение, которым пользуются почти миллион человек.Я использую сервис переднего плана для игрока.Я еще не реализовал MediaSession.У меня 99,95% сессий без сбоев.Так что это приложение работает на всех версиях, но я начал получать отчеты о сбоях (ANR) с Android 9. Этот сбой происходит только на Samsung телефонах, особенно s9, s9+, s10, s10+, note9 моделях.

Я пробовал эти,

  • Вызов startForeground() метода в onCreate()
  • Вызов Service.startForeground() до Context.stopService()
  • Другие ответы на вопросы stackoverflow на подобные вопросы

Я прочиталнекоторые комментарии от разработчиков Google, они сказали, что это просто Intended Behavior.Интересно, это произошло из-за системы Samsung или ОС Android.У кого-нибудь есть мнение по этому поводу?Как я могу это исправить?

Ответы [ 4 ]

1 голос
/ 28 мая 2019

Я ждал своего отчета о сбое, чтобы поделиться решением. Я не получил никакого крушения или ANR почти 20 дней. Я хочу поделиться своим решением. Это может помочь тем, кто сталкивается с этой проблемой.

В onCreate() метод

  • Прежде всего, мое приложение является мультимедийным приложением. Я еще не реализовал медиасессию. Я создаю канал уведомлений в верхней части onCreate(). Официальный документ
  • Я вызываю Service.startForeground() метод после Context.startForegroundService() метода. По моему prepareAndStartForeground() методу.

    Примечание: я не знаю почему, но ContextCompat.startForegroundService () не работает должным образом.

По этой причине я добавил вручную ту же функцию в свой класс обслуживания вместо вызова ContextCompat.startForegroundService()

private fun startForegroundService(intent: Intent) {
    if (Build.VERSION.SDK_INT >= 26) {
        context.startForegroundService(intent)
    } else {
        // Pre-O behavior.
        context.startService(intent)
    }
}

prepareAndStartForeground() метод

private fun prepareAndStartForeground() {
    try {
        val intent = Intent(ctx, MusicService::class.java)
        startForegroundService(intent)

        val n = mNotificationBuilder.build()
        // do sth
        startForeground(Define.NOTIFICATION_ID, n)
    } catch (e: Exception) {
        Log.e(TAG, "startForegroundNotification: " + e.message)
    }
}

Это мой onCreate()

override fun onCreate() {
    super.onCreate()
    createNotificationChannel()
    prepareAndStartForeground()
}

Мой onStartCommand()

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    if (intent == null) {
        return START_STICKY_COMPATIBILITY
    } else {
        //....
        //...
    }
    return START_STICKY
}

onRebind, onBind, onUnbind методы, подобные этим

internal var binder: IBinder? = null

override fun onRebind(intent: Intent) {
    stopForeground(true) // <- remove notification
}

override fun onBind(intent: Intent): IBinder? {
    stopForeground(true) // <- remove notification
    return binder
}

override fun onUnbind(intent: Intent): Boolean {
    prepareAndStartForeground() // <- show notification again
    return true
}

Нам нужно что-то очистить, когда onDestroy () вызывает

   override fun onDestroy() {
    super.onDestroy()
    releaseService()
   }

private fun releaseService() {
    stopMedia()
    stopTimer()
    // sth like these
    player = null
    mContext = null
    afChangeListener = null
    mAudioBecomingNoisy = null
    handler = null
    mNotificationBuilder = null
    mNotificationManager = null
    mInstance = null
}

Я надеюсь, что это решение работает правильно для вас.

0 голосов
/ 01 июля 2019

Я почти устранил проблему с startForeground () в методах MediaSessionCompat.Callback, таких как onPlay (), onPause ().

0 голосов
/ 04 июня 2019

Компонент Android Service немного сложен для правильной работы, особенно в более поздних версиях Android, где ОС добавляет дополнительные ограничения.Как упоминалось в других ответах, при запуске Service используйте ContextCompat.startForegroundService().Затем, в Service.onStartCommand(), немедленно позвоните startForeground().Сохраните Notification, который вы хотите показать в качестве поля члена, и используйте его, если оно не равно нулю.Пример:

private var notification:Notification? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    if (notification == null) {
        notification = createDefaultNotification()
    }
    startForeground(NOTIFICATION_ID, notification)

    // Do any additional setup and work herre

    return START_STICKY
}

Всегда возвращайте START_STICKY в вашем Service.Все остальное, вероятно, неправильно, особенно если вы делаете аудиоплеер любого рода.На самом деле, если вы работаете с аудиоплеером, вы не должны реализовывать свой собственный Сервис, а вместо этого использовать MediaBrowserServiceCompat (из AndroidX).

Я также рекомендую публикации в блоге, которые янаписал по этому поводу: https://hellsoft.se/how-to-service-on-android-part-3-1e24113152cd

0 голосов
/ 18 мая 2019

После той же проблемы с теми же телефонами, я сделал несколько изменений, и сбои исчезли.Я не уверен, что сделал трюк, но я предполагаю, что вызов startForeground в onCreate и onStartCommand.Я не уверен, зачем это нужно, если служба уже запущена и все было правильно вызвано в onCreate.

Другие изменения: - Изменение значения serviceId на какое-то небольшое число (1-10) - Реже вызывать startFororegroundService через одиночный вызовсинхронный класс (это было реализовано ранее при сбоях, чтобы предотвратить остановку службы до ее запуска с помощью обратного вызова от onStartCommand, но теперь он также фильтрует вызовы, если служба уже запущена).- использование START_REDELIVER_INTENT (не должно ни на что влиять)

Эта проблема возникает на указанных телефонах только для некоторых пользователей, поэтому я подозреваю, что она связана с некоторым новым обновлением от Samsung и в конечном итоге будет исправлена ​​

...