Подтвердить что ты не робот

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 не запускается вообще?

4b9b3361

Ответ 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);

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