AlarmManager, BroadcastReceiver и Service не работают
Я рефакторинг кода, так что мое приложение будет извлекать данные с веб-сайта один раз в день в определенное время. Из моих исследований кажется, что AlarmManager
является наиболее подходящим подходом.
Учебное пособие, которое я использовал, следующее: 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>
Когда я запускаю 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
не запускается вообще?
Ответы
Ответ 1
Выяснилось!
MyService должен расширять IntentService вместо Сервис!
С этим изменением это также означает, что вместо переопределения onStartCommand
вместо этого следует переопределять onHandleIntent
(см. docs на 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
Ответ 2
Вы можете заставить 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);
Это может решить вашу проблему!
Ответ 3
Вместо использования
Intent dailyUpdater = new Intent(context, MyService.class);
использование
Intent dailyUpdater = new Intent(this, MyService.class);
Другим предложением является запуск службы непосредственно из будильника, а не отправка широковещательной передачи и запуск службы в широковещательном приемнике.