Skocz do zawartości
ramzes0071

Thread, service i Task killer

    Rekomendowane odpowiedzi

    Witam.

    Robię aplikację która głównie ma być nie widoczna i pracować w tle, tylko co zadany przez użytkownika czas wyświetlać monit na ekranie o podanie kodu. Po niepoprawnym wpisaniu w tle uruchamiają się inne czynności. Chciałbym się zapytać co zastosować do tej pracy w tle. Czego mi nie ubije task killer? Najlepszy był by chyba service ale jak sprawdzałem to task killer go zatrzymał.

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    gzajac

    Task killer'y ubijają całą aplikację, w sensie całego procesu (wszystkie wątki). Nie ochronisz się przed tym.

    Ale jest rozwiązanie dla takiego problemu, które dodatkowo eliminuje konieczność ciągłego działania Service w tle. Poczytaj o AlarmManager'ze. W skrócie powinno to działać tak:

    1) aplikacja rejestruje się na otrzymanie zdarzenia (intent'a) BOOT_COMPLETED dzięki temu przy starcie systemu mamy możliwość ustawienia Alarm Manager'a - robimy to w BroadcastReceiver'ze który łapie to zdarzenie

    2) po ustawieniu Alarm Manager'a na periodyczne wysyłanie własnego INTENT'a, co określony czas uruchamiany jest kolejny BroadcastReceiver który ten Intent (zdarzenie) obsługuje. W tym BroadcastReceiverze nie można robić żadnych długotrwałych operacji bo dostaniesz ANR'a (Broadcast Receiver musi skończyć działanie w max 10 sekund). Ale w tym BR uruchamiasz Service w którym w osobnym wątku możesz robić długie operacje. Jeśli Service zrobi co do niego należy kończysz poprostu jego działanie i czekasz aż upłynie zadany czas aby Alarm Manager znów odpalił BR.

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach

    Mógłbyś mi trochę dokładnie opisać jak zaimplementować tego drugiego BroadcastReceivera, który obsługuje INTENT'a wysyłanego przez AlarmManagera?

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    gzajac

    Osobna klasa dziedzicząca po BroadcastReceiver:

    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    
    /**
    * Receiver that is periodically fired by AlarmManager. It should send a request
    * to {@link UpdateService} to get the latest data.
    *
    */
    public class OnAlarmReceiver extends BroadcastReceiver {
    
       @Override
       public void onReceive(Context context, Intent intent) {
           Intent in = new Intent(context, UpdateService.class);       
           context.startService(in);
       }
    }
    

    i w AndroidManifest.xml dodatkowy wpis:

    <receiver
      android:name=".OnAlarmReceiver">
    </receiver>

    AlarmManager powinien być ustawiony w taki sposób:

    public static void setAlarmManager(Context context, int period) {
    
       AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    
       Intent i = new Intent(context, OnAlarmReceiver.class);
       PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
    
       if (period > 0) {
           // Cancel existing alarm
           am.cancel(pi);
    
           // Set alarm with new update period value
           am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
                   + period, period, pi);
    
       } else {
           am.cancel(pi);
       }
    }
    

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach

    Mam do Ciebie jeszcze jedną prośbę. Jakbyś mógł mi pokazać jak zrobić tego pierwszego BroadcastReceivera bo mam problem żeby w nim odpalić Alarm Managera. Zrobiłem sobie przykładowe Activity i tak uruchamiam AlarmManagera i działa ale w BroadcastReceiverze nie wiem jak zrobić BOOT_COMPLETED.

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    gzajac

    OnBootBroadcastReceiver może wyglądać np tak

    /**
    * Receiver that is fired during every system boot.
    *
    */
    public class OnBootReceiver extends BroadcastReceiver {   
    
       @Override
       public void onReceive(Context context, Intent intent) {
    
           //Set alarm manager here - use what I provided in the previous post 
       }
    }

    I w AndroidManifest.xml dodać 2 rzeczy:

    1)

    <receiver
       android:name=".OnBootReceiver">
       <intent-filter>
           <action
               android:name="android.intent.action.BOOT_COMPLETED">
           </action>
       </intent-filter>
    </receiver>

    2)

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach

    Ok zadziałało tylko troche nie do końca. Ten service który jest uruchamiany przez drugiego BroadcastReceivera nadal działa w tym samym wątku i jak ubije aplikacje to sie później już nie uruchomi ponownie.

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    gzajac
    Ten service który jest uruchamiany przez drugiego BroadcastReceivera nadal działa w tym samym wątku i jak ubije aplikacje to sie później już nie uruchomi ponownie

    Osobny wątek odpalasz sobie w metodzie onStartCommand() Twojego service'a (operacje które wykonuje Service nie powinny być robione w głównym wątku aplikacji). To musisz zrobić ręcznie, chyba że użyjesz fajnej klasy IntentService, która odpala wątek automatycznie (do poczytania w dokumentacji).

    Nie pisałem CI nigdzie że automatycznie dostaniesz osobny wątek stosując powyższy trick z Receiverami.

    Dodatkowo, jak ubijesz aplikację (albo zostanie ubita przez system), to gdy wyzwoli się AlarmManager, automatycznie zostanie uruchomiona aplikacja (w sensie procesu aplikacji), w jej głównym wątku odpalony zostanie OnAlarmBroadcastReceiver i następnie Service, który odpala sobie swój wątek do czasochłonnych operacji. I tak dalej...

    Edytowane przez gzajac

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach

    Nie moge w ogóle użyć tej metody onStartCommand. Cały czas wyświetla mi się następujący błąd: The method onStartCommand(Intent, int, int) of type UpdateService must override or implement a supertype method.

    Nie ma nawet nigdzie pokazanego jakiegoś przykładowego IntentServicea.

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    gzajac
    The method onStartCommand(Intent, int, int) of type UpdateService must override or implement a supertype method.

    Czyli musisz zawołać w swojej implementacji metodę z klasy nadrzędnej albo ją przeciążyć. Dokładnie to Ci napisał kompilator.

    Masz wogóle zaimplementowaną klasę UpdateService?

    Więcej kodu Ci nie wkleję bo nie mam za bardzo czasu na usuwanie fragmentów których nie mogę udostępniać.

    Możesz sobie poczytać coś na ten temat np tutaj:

    IntentService on Android– asynchronous background tasks made easy. at 9MMEDIA Blog

    Pony Express Tutorial Part 2a: Are You Being Served? | Well, I found it interesting..

    Class derived from IntentService must have default constructor - Android Developers | Google Groups

    I jeszcze pełno innych rzeczy google pokazuje -> trzeba już poszukać samemu.

    Edytowane przez gzajac

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach

    Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

    Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

    Zarejestruj nowe konto

    Załóż nowe konto. To bardzo proste!

    Zarejestruj się

    Zaloguj się

    Posiadasz już konto? Zaloguj się poniżej.

    Zaloguj się

    • Ostatnio przeglądający   0 użytkowników

      Brak zarejestrowanych użytkowników przeglądających tę stronę.

    x