Как запустить сервис в отдельном потоке

Имею два сервиса для уведомлений и воспроизведения аудио. Пробовал использовать IntentService, но работало не корректно и насколько я понял, startForegroundService() доступен только в android >= 8.

Также знаю, что можно использовать Thread или Handler, но не имею представления как организовать это, так как не нашел подходящих примеров.

А именно, где организовывать новый поток в самом сервисе, или в активности, или как-то по другому?

Логи для ответа

D/ViewRootImpl@36c1a31[MainActivity]: ViewPostIme pointer 0
D/ViewRootImpl@36c1a31[MainActivity]: ViewPostIme pointer 1
I/System.out: StartService
D/ViewRootImpl@36c1a31[MainActivity]: ViewPostIme pointer 0
D/ViewRootImpl@36c1a31[MainActivity]: ViewPostIme pointer 1
I/System.out: Destroy
// проверка кнопки
D/ViewRootImpl@36c1a31[MainActivity]: ViewPostIme pointer 0
D/ViewRootImpl@36c1a31[MainActivity]: ViewPostIme pointer 1
I/System.out: StartService
// запуск, далее сворачивание приложения
D/ViewRootImpl@36c1a31[MainActivity]: MSG_WINDOW_FOCUS_CHANGED 0 1
D/InputMethodManager: prepareNavigationBarInfo() DecorView@fa672d7[MainActivity]
D/InputMethodManager: getNavigationBarColor() -855310
D/InputTransport: Input channel destroyed: 'ClientS', fd=68
I/mali_egl: eglDestroySurface() in
I/mali_winsys: delete_surface() [1080x2340] return
I/mali_egl: eglDestroySurface() out
W/libEGL: EGLNativeWindowType 0x7760d9af50 disconnect failed
D/ViewRootImpl@36c1a31[MainActivity]: Relayout returned: old=(0,0,1080,2340) new=(0,0,1080,2340) req=(1080,2340)8 dur=10 res=0x5 s={false 0} ch=true
D/ViewRootImpl@36c1a31[MainActivity]: stopped(true) old=false
// в течении минуты
I/System.out: Destroy

Ответы (2 шт):

Автор решения: Alexander Chernin

При помощи Thread вот так:

public class MyService extends Service {

    private Thread myThread = new MyThread();

    public MyService() {
        super();
    }

    public int onStartCommand(Intent intent, int flags, int startId) {
        // Если поток не запущен, то запустить
        if (!myThread.isAlive())
            myThread.start();

        return ...;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    // Поток
    private class MyThread extends Thread {

        @Override
        public void run() {
            // Делаем что-то долгое и нудное/нужное
        }
    }
}
→ Ссылка
Автор решения: Shadowlight

Решением для меня стал этот ответ - https://stackoverflow.com/questions/44425584/context-startforegroundservice-did-not-then-call-service-startforeground/46449975#46449975

Это нужно добавить в onCreate()

  if (Build.VERSION.SDK_INT >= 26) {
        String CHANNEL_ID = "my_channel_01";
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                "Channel human readable title",
                NotificationManager.IMPORTANCE_DEFAULT);

        ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);

        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("")
                .setContentText("").build();

        startForeground(1, notification);
    }

Если у вас есть свои уведомления, то вы можете завершать это уведомление в onStartCommand() так:

stopForeground(true);

Да, это не очень красиво, но без вибрации и сигнала не заметно (пропадет через секунду). И не забудьте заменить создание уведомлений в вашем сервисе на

startForeground(123, notification);

Без этого работать на версиях >= api 26 не будет. Но возможно есть и другой способ.

→ Ссылка