13

Я пересматриваю код, чтобы мое приложение извлекало данные с веб-сайта один раз в день в определенное время. Из моих исследований кажется, что AlarmManager - наиболее подходящий подход.AlarmManager, BroadcastReceiver и Service не работают

В учебнике я следующее: http://mobile.tutsplus.com/tutorials/android/android-fundamentals-downloading-data-with-services/

До сих пор, кажется, работает AlarmManager и BroadcastReceiver, однако Service кажется, никогда не заводится (т. Е onStartCommand не кажется, называется)

Вот важные фрагменты кода, который я до сих пор:

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> 

Когда я тр igger setRecurringAlarm в MyActivity журнал печатает, как ожидалось, аналогично, каждые 15 минут появляется журнал от AlarmReceiver. Тем не менее, я никогда не видел журнал из MyService :(

пример того, что я вижу в журналах:

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 

Не могу понять, что я сделал неправильно - мое понимание от Android Dev Docs является то, что в AlarmReceiver, когда я звоню context.startService(dailyUpdater), который должен в свою очередь, вызов onStartCommand в MyService, хотя это, кажется, не будет так!

что я делаю неправильно, что вызывает MyService не начинать вообще?

+0

+1 Спасибо код мне помочь .. – Nirali

+0

Вы также работаете в неочевидное поведение wakelock запуска услуги в ответ на сигналы тревоги. Есть несколько подробностей и рекомендаций в ответах на http://stackoverflow.com/questions/25852309/does-alarmmanager-require-the-pendingintent-to-be-of-type-broadcastreceiver – ctate

ответ

15

Понял это!

MyService следует расширение IntentService вместо службы!

С этим изменением, это также означает, что вместо того, чтобы переопределение onStartCommand должно быть главной onHandleIntent вместо (см документацию на IntentService)

Так MYSERVICE теперь выглядит следующим образом:

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; 
     } 
    } 
} 

Примечание : В документах реализация по умолчанию onBind возвращает null, поэтому нет необходимости ее переопределять.

Более подробную информацию о расширении IntentService: http://developer.android.com/guide/topics/fundamentals/services.html#ExtendingIntentService

+1

+1 Спасибо, мой код мне помог. – Nirali

+1

+1 Спасибо! Класс« Сервис »отлично работает на устройствах Android 4.x но я не мог тренироваться, почему он не работал на устройствах Android 2.x. При переходе на «IntentService» это работало как шарм. Извлеченные уроки! –

0

Вы можете получить AlarmManager запустить службу сразу, а не идти через BroadcastReceiver, если вы измените свое намерение так:

//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); 

Это может решить вашу проблему!

+0

Спасибо за предложение - я попробовал это раньше (хотя без downloader.addFlags), и это не сработало - попробуйте с addFlags и посмотрим, поможет ли это! Просто интересно, почему существует «BroadcastReceiver», если вы можете просто запустить службу напрямую? – pyko

+0

Пробовал это изменение - не работал :(также пытался изменить 'context' на' this', как предложил kumar ... не повезло! – pyko

0

Вместо использования

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

использование

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

Другое предложение запустить службу непосредственно от тревоги, а не посылать широковещательные и запуск службы в радиовещательного приемника.

+0

вы пробовали ур код без downloader.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK); –

+0

привет kumar, да, я считаю, что я действительно пробовал это без 'addFlags', также не работал. – pyko