13

Reorganizuję kod, aby moja aplikacja pobierała dane ze strony internetowej raz dziennie o określonej godzinie. Z moich badań wynika, że ​​najbardziej odpowiednim podejściem jest AlarmManager.AlarmManager, BroadcastReceiver i usługa nie działa

Tutorial śledzę to: http://mobile.tutsplus.com/tutorials/android/android-fundamentals-downloading-data-with-services/

Dotychczas AlarmManager i BroadcastReceiver wydają się działać, jednak Service nigdy nie wydaje się uruchomić (tj. onStartCommand nie wydaje się być nazywany)

Oto istotne fragmenty kodu mam tak daleko:

MyActivity.java

private void setRecurringAlarm(Context context) { 
    Calendar updateTime = Calendar.getInstance(); 
    updateTime.setTimeZone(TimeZone.getDefault()); 
    updateTime.set(Calendar.HOUR_OF_DAY, 20); 
    updateTime.set(Calendar.MINUTE, 30); 

    Intent downloader = new Intent(context, AlarmReceiver.class); 
    downloader.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, downloader, PendingIntent.FLAG_CANCEL_CURRENT); 
    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 
    // should be AlarmManager.INTERVAL_DAY (but changed to 15min for testing) 
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent); 
    Log.d("MyActivity", "Set alarmManager.setRepeating to: " + updateTime.getTime().toLocaleString()); 
} 

AlarmReceiver.java

public class AlarmReceiver extends BroadcastReceiver { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     Intent dailyUpdater = new Intent(context, MyService.class); 
     context.startService(dailyUpdater); 
     Log.d("AlarmReceiver", "Called context.startService from AlarmReceiver.onReceive"); 
    } 
} 

MyService.java

public class MyService extends Service { 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     Log.d("MyService", "About to execute MyTask"); 
     new MyTask().execute(); 
     return Service.START_FLAG_REDELIVERY; 
    } 

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

    private class MyTask extends AsyncTask<String, Void, boolean> { 
     @Override 
     protected boolean doInBackground(String... strings) { 
      Log.d("MyService - MyTask", "Calling doInBackground within MyTask"); 
      return false; 
     } 
    } 
} 

AndroidManifest.xml

<application ...> 
    ... 
    <service android:name="MyService"></service> 
    <receiver android:name="AlarmReceiver"></receiver> 
</application> 

Kiedy tr igger the setRecurringAlarm w MyActivity log zostanie wydrukowany zgodnie z oczekiwaniami, podobnie, co 15 minut pojawi się log z AlarmReceiver. Jednak nie widzę dziennik z MyService :(

przykładem tego, co widzę w dziennikach:

DEBUG/MyActivity(688): Set alarmManager.setRepeating to: Jan 29, 2012 8:30:06 PM 
DEBUG/AlarmReceiver(688): Called context.startService from AlarmReceiver.onReceive 
DEBUG/AlarmReceiver(688): Called context.startService from AlarmReceiver.onReceive 

nie może wydawać się, aby dowiedzieć się, co zrobiłem źle - moje rozumienie ze Android Dev Docs jest to, że w AlarmReceiver gdy zgłoszę context.startService(dailyUpdater) które powinny z kolei wezwanie onStartCommand w MyService, chociaż nie wydaje się być przypadek!

Co robię źle, że jest przyczyną MyService aby nie zacząć

w ogóle
+0

+1 Dzięki kod mi pomóc .. – Nirali

+0

Ty również uruchomiony w nieoczywistych zachowań blokada wybudzenia z usług począwszy od odpowiedzi na alarmy. Jest kilka szczegółów i rekomendacji w odpowiedziach na http://stackoverflow.com/questions/25852309/does-alarmmanager-require-the-pendingintent-to-be-of-type-broadcastreceiver – ctate

Odpowiedz

15

Wyliczyłem to!

MyService należy rozszerzenie IntentService zamiast usługi!

Dzięki tej zmianie, oznacza to również, że zamiast przesłanianie onStartCommand powinno być nadrzędnym onHandleIntent zamiast (patrz dokumenty dotyczące IntentService)

Więc MyService teraz wygląda tak:

public class MyService extends IntentService { 

    public MyService() { 
     super("MyServiceName"); 
    } 

    @Override 
    protected void onHandleIntent(Intent intent) { 
     Log.d("MyService", "About to execute MyTask"); 
     new MyTask().execute(); 
    } 

    private class MyTask extends AsyncTask<String, Void, boolean> { 
     @Override 
     protected boolean doInBackground(String... strings) { 
      Log.d("MyService - MyTask", "Calling doInBackground within MyTask"); 
      return false; 
     } 
    } 
} 

Note : Z dokumentacji domyślna implementacja onBind zwraca null, więc nie ma potrzeby jej przesłonić.

Więcej informacji o rozszerzenie IntentService: http://developer.android.com/guide/topics/fundamentals/services.html#ExtendingIntentService

+1

+1 Dzięki, że Twój kod pomógł mi – Nirali

+1

+1 Dzięki! Klasa" Service "działa dobrze na urządzeniach z Androidem 4.x ale nie mogłem poćwiczyć, dlaczego nie działało na urządzeniach z Androidem 2.x. Po przejściu na "IntentService" działało jak czar. –

0

Można dostać AlarmManager uruchomić usługę od razu, a nie przechodzi BroadcastReceiver, jeśli zmienisz zamiar tak:

//Change the intent 
Intent downloader = new Intent(context, MyService.class); 
    downloader.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 

//Change to getService() 
PendingIntent pendingIntent = PendingIntent.getService(context, 0, downloader, PendingIntent.FLAG_CANCEL_CURRENT); 

To może rozwiązać Twój problem!

+0

Dzięki za sugestię - próbowałem tego wcześniej (choć bez downloader.addFlags) i nie działało - spróbuje z addFlags i zobaczy, czy to pomaga! Zastanawiasz się, dlaczego istnieje "BroadcastReceiver", jeśli możesz po prostu uruchomić usługę bezpośrednio? – pyko

+0

Próbowałem tej zmiany - nie działało :(próbowałem również zmienić 'context' na' this' jak zasugerował kumar ... bez powodzenia! – pyko

0

Zamiast

Intent dailyUpdater = new Intent(context, MyService.class);

korzystanie

Intent dailyUpdater = new Intent(this, MyService.class);

Inne sugestia jest rozpoczęcie usługi bezpośrednio z alarmem, zamiast wysyłania transmisję i uruchamiania usługi w odbiorniku transmisji.

+0

czy próbowałeś kod ur bez downloader.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK); –

+0

cześć kumar, tak wierzę, że spróbowałem go bez 'addFlags' również, też nie działa – pyko