Android Kotlin Foregeground Service + Уведомления, почему работает неправильно? - PullRequest
0 голосов
/ 03 ноября 2019

В моем приложении мне нужна служба переднего плана, которая будет проверять определенное условие каждую минуту, и, если оно верно, оно вызывает напоминание об уведомлении. Пользователь заранее определяет, во сколько и в какое время он хотел бы получить напоминание. Данные сохраняются в базе данных. Затем служба каждую минуту проверяет, есть ли у нее напоминание на определенный час и день, и если да, отправляет уведомление. Служба должна работать, когда пользователь использует приложение, когда приложение работает в фоновом режиме и когда оно закрыто. Может кто-нибудь сказать мне, почему этот код работает на одном телефоне, но не на других? Так называемый, если я устанавливаю напоминание, до 20 минут, это работает (во всех 3 состояниях, о которых я писал ранее), но как только я установил напоминание на следующие дни, оно больше не работает. Я удивлен, что иногда напоминание на другом телефоне работает, а иногда нет. Я проверил, в настройках выбрано разрешение на запуск приложения в фоновом режиме. Пожалуйста, помогите.

Манифест

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
            android:allowBackup="false"
            android:icon="@drawable/pills"
            android:label="@string/nameOfApplications"
            android:roundIcon="@drawable/icon"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
        <service
                android:name=".ForegroundService"
                android:enabled="true"
                android:exported="true"/>
        <activity android:name=".MainActivity">

            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

ForegroundService

class ForegroundService : Service() {
    companion object {
        val CHANNEL_ID = "ForegroundServiceChannel"
        val CHANNEL_ID_CHILD = "ForegroundServiceChannelCHILD"
        private var  isRunning = false
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        val input = intent.getIntExtra("time",15)
        createNotificationChannel()
        val notificationIntent = Intent(this, Menu::class.java)
        val pendingIntent = PendingIntent.getActivity(
            this,
            0, notificationIntent, 0
        )

        val notification = NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("MotherNotification")
            .setContentText("Message")
            .setOnlyAlertOnce(true)
            .build()

        startForeground(1, notification)
        isRunning = true
        val context = this
        val intent = Intent(this, ShowAll::class.java)
        val pendingIntentNotification = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        doAsync {
            while(isRunning)
            {
                var message : String = createReminderMessage(context)

                //SystemClock.sleep(input * 10_000L)
                SystemClock.sleep(50000)
                uiThread {
                    if(isRunning && (message != "Nadszedł czas by zażyć: ")) {
                        val notification = NotificationCompat.Builder(context, CHANNEL_ID_CHILD)
                            .setContentTitle("Title")
                            .setContentText(message)
                            .setContentIntent(pendingIntentNotification)
                            .setAutoCancel(true)
                            .build()
                        with(NotificationManagerCompat.from(context)) {
                            notificationManager.notify(2, notification)
                        }
                    }
                }
            }
        }

        return START_NOT_STICKY
    }




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

    override fun onDestroy() {
        super.onDestroy()
        isRunning = false
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val serviceChannel = NotificationChannel(
                CHANNEL_ID,
                "Foreground Service Channel",
                NotificationManager.IMPORTANCE_DEFAULT

            )
            val serviceChannel2 = NotificationChannel(
                CHANNEL_ID_CHILD,
                "Foreground Service ChannelChild ",
                NotificationManager.IMPORTANCE_DEFAULT
                //NotificationManager.IMPORTANCE_LOW
            )

            val manager = getSystemService(NotificationManager::class.java)
            manager.createNotificationChannel(serviceChannel)
            manager.createNotificationChannel(serviceChannel2)
        }
    }

    fun reminderForNow(context: Context) : ArrayList<Reminder> {
        var listOfReminder : ArrayList<Reminder> = ArrayList()
        var timetoday = takeTimeNow()
        var dateToday = takeTodayDate()

        val dbHelper = SQLConector(context)
        val allRemindersList = dbHelper.getAllReminders()
        for (i: Reminder in allRemindersList) {

            if (i.reminderDate == dateToday && i.ReminderTime == timetoday) {
                var reminder = Reminder(
                    i.id,
                    i.Name,
                    i.reminderDate,
                    i.ReminderTime
                )
                listOfReminder.add(reminder)
            }
        }
        return listOfReminder
    }

    private fun createReminderMessage(p0: Context) : String{
        var message : String = "title : "
        var listOfReminders = reminderForNow(p0)
        if(listOfReminders.count() > 0){
            for (i: Reminder in listOfReminders) {
                message += i.Name + ", "
            }
        }
        return message
    }

 private fun takeTodayDate():String{
        val current = LocalDateTime.now()
        val formatDate = DateTimeFormatter.ofPattern("yyyy-MM-dd")
        var dateResult = current.format(formatDate).toString()
        return  dateResult
    }

    private fun takeTimeNow() : String{
        val current = LocalDateTime.now()
        val formatTime = DateTimeFormatter.ofPattern("HH:mm")
        var timeResult = current.format(formatTime).toString()
        return  timeResult

    }

}

Основная деятельность

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        binding.buttonStart.setOnClickListener { startService() }
        binding.buttonStop.setOnClickListener {stopService()  }
        startService()
    }


    private fun startService() {
        val serviceIntent = Intent(this, ForegroundService::class.java)
        serviceIntent.putExtra("time", 1)

        ContextCompat.startForegroundService(this, serviceIntent)
    }

    private fun stopService() {
        val serviceIntent = Intent(this, ForegroundService::class.java)
        stopService(serviceIntent)
    }

}

1 Ответ

0 голосов
/ 03 ноября 2019

Правильный способ справиться с задачами, требующими точного времени срабатывания, - это использовать класс AlarmManagerCompat .

Вы можете использовать метод setExactAndAllowWhileIdle(...), чтобы заставить службу тревоги запускать службу, даже когдаустройство находится в режиме ожидания, и вам потребуется BroadcastReceiver для повторного планирования аварийных сигналов, если устройство будет перезагружено.

В Интернете можно найти некоторые рекомендации о том, как это реализовать.

...