Pokazanie powiadomienia z usługi (JobScheduler)

0

Słuchajcie, mam taki oto problem. Testuję, jak działa Firebase Job Scheduler, mam taki kod (w sumie na razie to copy-paste z dokumentacji oficjalnej):

Stworzenie joba:

FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));

Job myJob = dispatcher.newJobBuilder()
                .setService(MyJobService.class) // the JobService that will be called
                .setTag("my-unique-tag")        // uniquely identifies the job
                .setTrigger(Trigger.executionWindow(0, 5))
                .build();

        dispatcher.mustSchedule(myJob);

I teraz chcę, żeby gdy job się wykona, zostało wyświetlone powiadomienie:

public class MyJobService extends JobService
{
    @Override
    public boolean onStartJob(JobParameters job)
    {
        // Do some work here

        sendNotification("TEST");

        return true; // Answers the question: "Is there still work going on?"
    }

    @Override
    public boolean onStopJob(JobParameters job)
    {
        return false; // Answers the question: "Should this job be retried?"
    }

    private void sendNotification(String messageBody)
    {
        Log.d("TEST","Notification: " + messageBody);

        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);

        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("Job executed")
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }
}

Faktycznie job się wykonuje (mogę to sprawdzić jak debugguję aplikację, komunikat w logcat też się wyświetla). Ale powiadomienie nigdy nie jest pokazywane. Nie ma nigdzie żadnego błędu, po prostu nie pokazuje powiadomienia. Ktoś może podpowie, co robię nie tak?

0

Obstawiam Manifest. Zamień

<service
  android:name=".MyJobService"
  android:enabled="false"/>

na

<service
  android:name=".MyJobService"
  android:enabled="true"/>

Przy okazji z onStartJob() możesz zwracać false, bo nic i tak nie wykonujesz na wątku po wysłaniu notyfikacji. No i jak @dbCooper napisał - dla Oreo trzeba ustawić Channel. NotificationManagerCompat tutaj nie jest potrzebny. Ten standardowy możesz zostawić. Jak to nie kwesita Manifestu, to nie mam pojęcia. Wszystko wygląda dobrze dla SDK < 26.

EDIT:
Zmieniłem zdanie. Jak w logasz widzisz, że serwis się wykonuje, to nie mam pojęcia. Jaki telefon i z którą wersją? Jak wysyłasz notyfikację po prostu np. za pomocą kliknięcia to przychodzi czy nie?

0

Wszystko już wiem. Nie działało na Oreo, tak jak napisał @dbCooper. Właśnie normalnie z kliknięcia też nie działało.

Za to te joby wykonują się jak chcą, ustawię 5 jobów w pętli, a wykonają się dwa, albo tylko jeden. Czy w ogóle istnieje pewny sposób na zaplanowanie tego gdy apka jest zamknięta? Bez drenowania baterii (AlarmManager też problemu nie rozwiązuje)

P.S. target sdk 27, nie 26

0

Masz ustawiony execution window na 0, 5 czyli Job wystartuje albo 0 albo 1 albo 2 3 4 5 sekund od teraz.

Moze napisz jaki efekt chcesz osiągnać. Wyswietlac Notyfikacje co 5 sekund czy cos innego?

0

Potrzeba mi kilkanaście jobów na wydarzenia z kalendarza, docelowo nie będą oczywiście wykonywać się na raz - chociaż może zdarzyć się 2-3 w tym samym terminie.

0

W takim razie wyglada na to ze musisz sobie odpowiednio policzyc Execution Window.

BTW Mozesz tez sprobowac libki https://github.com/evernote/android-job Jest sprawdzona i uznana w srodowisku. Laczy w sobie JobScheduler, FirebaseDispatcher i AlertManager. Sama wybiera najlepszy sposob w zaleznosci od api itp.

0

Widziałem to i chyba umożliwia ustawienie konkretnego czasu powiadomienia. Problem w tym, że (przynajmniej z tego co piszą), alarmy się wyzerują jeśli usuniesz aplikację z historii. A mi zależy na powiadomieniach offline także wtedy, gdy aplikacja jest zatrzymana, a nie chcę trzymać wakelocka. Tam piszą, że AlarmManager tak działa i nie da się tego tak zrobić.

P.S. taki kod:

for(int i=0;i<5;i++)
        {
            FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));

            dispatcher.mustSchedule(dispatcher.newJobBuilder()
                    .setService(MyJobService.class) // the JobService that will be called
                    .setTag("my-unique-tag" + i)        // uniquely identifies the job
                    .setLifetime(Lifetime.FOREVER)
                    .setTrigger(Trigger.executionWindow(i, 4))
                    .build());

        }

I wykonał sie tylko jeden Job. Czy ja tu czegoś nie rozumiem?

A tak:

setTrigger(Trigger.executionWindow(i, 4))

Wykonają się 2 joby jednocześnie, natychmiast po zakolejkowaniu (a nie po 4 sekundach).

0

W kodzie Joba. Po wyslaniu notyfikacji powinienes zwrocic false. Wyslales notyfikacje i tyle czyli "Is there still work going on?". No.

    @Override
    public boolean onStartJob(JobParameters job)
    {
        // Do some work here
 
        sendNotification("TEST");
 
        return false;
    }

Ta linijke wyciagnij nad for. Wystarczy ci jeden dispatcher.
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));

Tworzysz 5 jobow ktore po kolei maja ExecutionWindow:

  1. (0, 4)
  2. (1, 4)
  3. (2, 4)
  4. (3, 4)
  5. (4, 4)

Teoretycznie Job 1 i 3 moga wykonac sie w tym samym momencie - Na przyklad Job 1 i 3 trzy sekundy po zaschedulowaniu. Takich par jest wiecej.

Na razie napisz petle tak zeby ExecutionWindowy ustawily sie na przyklad w ten sposob:

  1. (0, 1)
  2. (2, 3)
  3. (4, 5)
  4. (5, 6)
  5. (7, 8)

Wtedy nic nie bedzie kolidowac.

Piszac jeszcze inaczej jezeli chcesz zeby notyfikacja pojawila sie za minutę ExecutionWindow powinien byc na przykład (60, 61) czyli "Wykonaj tego Joba za minimum 60 sekund od teraz ale nie za 61 sekund lub dluzej"

0

Niestety, joby się nie wykonują po usunięciu aplikacji z historii. Czyli jest to bezużyteczne. Tak samo, jak ta biblioteka, którą podałeś. Czy w ogóle da sie to zrobić na Androidzie? Nie chcę, żeby aplikacja działała ciągle w tle i drenowała baterię.

Z drugiej strony, Kalendarz Google ma powiadomienia offline, więc musi się dać.

0

Przez usunięcie aplikacji z historii masz na myśli usunięcie procesu aplikacji czy coś innego? Bo jak to pierwsze, to nigdy nie miałem takiego problemu (a jak miałem to z jakimiś telefonami typu NoName™). No i jak sprawdzasz w takim wypadku czy serwis się nie wykonał?

0

Nie no, mam na myśli usunięcie z historii, czyli przycisk listy ostatnich, stamtąd usuwasz. Nie ubicie siłowe procesu. Jednak działa. Tzn, ta biblioteka Firebase działa, odpala sie nawet gdy usunę z historii. Działa także po restarcie urządzenia, zaplanowany job sie odpala i pokazuje powiadomienie, czyli ok - trzeba tylko dodać odpowiednią flagę w manifeście (swoją drogą, mogliby to dodać u siebie, merged manifest załatwiłby sprawę). Zastanawiam się tylko, czy zadziała to, jak poustawiam joby na kilka miesięcy naprzód (trzeba odliczyć sekundy, bo nie ma ustawiania po dacie).

Za to ta biblioteka android-job przestaje działać po usunięciu aplikacji z historii i wygląda na to, że nic nie można z tym zrobić. Oni sami piszą, że to kwestia backendu (AlarmManager) i nie da się nic na to poradzić, mocno jednak wątpię że to prawda. W każdym razie, jest bezużyteczna. Nie bardzo mi się podoba, api jest bardziej skomplikowane, każą coś inicjalizować w App, gdzie Firebase nie wymaga tego.

0
dbCooper napisał(a):

Ta linijke wyciagnij nad for. Wystarczy ci jeden dispatcher.
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));

Jest jedno zasadnicze pytanie, czy jeśli zaplanuję jakieś joby, zamknę aplikację albo nawet zrestartuję telefon, a następnie ponownie uruchomię aplikację i wykonam taki kod:

FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));`
dispatcher.cancelAll();

Chodzi mi o to, że mam dispatcher zawsze tworzony tak jak powyżej (z takim samym kontekstem), to czy po ponownym uruchomieniu aplikacji mogę anulować joby utworzone poprzednio, przed zamknięciem aplikacji.

0

No to sam sobie odpowiem na pytanie: TAK

1 użytkowników online, w tym zalogowanych: 0, gości: 1