AlarmManager и BroadcastReceiver вместо Service - это плохо? (Тайм-аут)

ИНФОРМАЦИЯ ОБ ИСТОРИИ:

Мне нужно обновить некоторые данные из Интернета, примерно каждый час или около того, даже когда мое приложение закрыто. Обновление самих данных занимает от 40 секунд до 1 минуты. Затем он сохраняется как Serializable для файла. Этот файл читается при запуске моего приложения.

ЭТО ПОДХОДИТ, ЧТО Я ПРИНИМАЮ ДЛЯ МОМЕНТА (не используя Сервис)

используйте AlarmManager и BroadcastReceiver следующим образом:

private void set_REFRESH_DATA_Alarm(){
    mContext = Main.this;
    alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    broadcast_intent = new Intent(mContext, 
            RepeatingAlarmReceiver_REFRESH_DATA.class);
    pendingIntent = PendingIntent.getBroadcast(mContext, 0,  broadcast_intent, 0);
    // do a REFRESH every hour, starting for the first time in 30 minutes from now ...
    Calendar now = Calendar.getInstance();
    long triggerAtTime = now.getTimeInMillis()+ (1 * 30 * 60 * 1000); // starts in 30 minutes
    long repeat_alarm_every = (1 * 60 * 60 * 1000); // repeat every 60 minutes
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtTime, 
            repeat_alarm_every, pendingIntent);
}

My RepeatingAlarmReceiver_REFRESH_DATA.class выполняет обновление данных из Интернета:

public class RepeatingAlarmReceiver_REFRESH_DATA extends BroadcastReceiver {

    public static Context mContext;
    ConnectivityManager mConnectivity;

    @Override
    public void onReceive(Context context, Intent intent) {
        mContext = context;
        // if Network connection is OK (Wifi or Mobile) then Load data ...
        mConnectivity = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        Log.i("Hub",
                "mConnectivity.getNetworkInfo(0)="
                        + mConnectivity.getNetworkInfo(0));
        Log.i("Hub",
                "mConnectivity.getNetworkInfo(1)="
                        + mConnectivity.getNetworkInfo(1));
        if ((mConnectivity.getNetworkInfo(0).getState() == NetworkInfo.State.CONNECTED)
                || (mConnectivity.getNetworkInfo(1).getState() == NetworkInfo.State.CONNECTED)) {
            Log.i("Hub", "Connectivity OK ...");
            Refresh_HIST_DATA();
        } else {
            // else Show Dialog "No network connection" ...
            Log.i("Hub",
                    "No network connection for the moment... will try again later!");
        }
    }

    // =========================================================================
    private void Refresh_HIST_DATA() {
        Log.i("Hub", "Refresh_HIST_DATA()... Starting ...");
        // etc...
    }
}

В манифесте у меня есть:

<receiver android:name="com.cousinHub.myapp.RepeatingAlarmReceiver_REFRESH_DATA" android:process=":remote" />

ПРОБЛЕМА:

Тревога срабатывает вовремя и начинается обновление, но затем примерно через 10 секунд он останавливается (Timeout):

06-25 11: 55: 05.278: WARN/ActivityManager (76): время ожидания трансляция BroadcastRecord {44bb4348 ноль} - [email protected]

06-25 11: 55: 05.278: WARN/ActivityManager (76): приемник во время таймаута: ResolveInfo {44bb42c0 com.cousinHub.myapp.RepeatingAlarmReceiver_REFRESH_DATA p = 0 o = 0 m = 0x0}

06-25 11: 55: 05.278: INFO/Процесс (76): Сигнал отправки. PID: 819 SIG: 9

06-25 11: 55: 05.298: INFO/ActivityManager (76): процесс com.cousinHub.myapp: remote (pid 819) умер.

ps: как ни странно, этот "тайм-аут" не происходит примерно через 10 секунд на моем HTC Hero (все еще на Android 1.5 - API Level 4), но хорошо на моем Nexus One (2.1-update1)

Вопросы:

  • Почему этот тайм-аут? Любой простой способ избежать этого?
  • Я правильно настроил свой BroadcastReceiver в манифесте? Мне нужно что-то добавить (чтобы избежать этого таймаута)?
  • Должен ли я полностью обратиться за Сервисом для этой функции "Обновить из Интернета"? (учитывая эту статью: http://www.androidguys.com/2009/09/09/diamonds-are-forever-services-are-not/) Если ДА (я должен переключиться на услугу): Любые хорошие фрагменты кода/учебника для этого...

Как всегда, спасибо за вашу помощь.

Н.

Ответы

Ответ 1

Почему этот тайм-аут?

Вы работаете в основном потоке приложения. Вы не можете запускать основной поток приложений более нескольких секунд. Кроме того, при этом вы наносите вред производительности устройства (потому что вы работает с приоритетом переднего плана), например, вызывая потерю частоты кадров в играх или видео.

Любой простой способ избежать этого?

Не выполняйте значительную работу ( > 100 мс) в основной теме приложения. Предложите делегату BroadcastReceiver IntentService, возможно WakefulIntentService.

Я установил свой BroadcastReceiver правильно в манифесте?

Пожалуйста, пожалуйста, пожалуйста, пожалуйста, избавитесь от android:process=:remote. Вам это не нужно, это вам не помогает, и это еще больше ухудшает производительность устройства.

Должен ли я полностью пойти на службу для такого рода "Обновление из Интернета" функциональность? (учитывая это статья: http://www.androidguys.com/2009/09/09/diamonds-are-forever-services-are-not/) Если ДА (я должен переключиться на услугу): Любые хорошие фрагменты кода/учебника для это...

ИМХО, да. И снова я написал это сообщение в блоге. Например, см. Проект WakefulIntentService.

Ответ 2

Для информации, я пробовал с новым потоком, и он работает, когда на Wifi (требуется около 1'30 "для обновления данных, когда телефон спит, он не получает" убит "!

//let try with a new separate thread ?
        new Thread(new Runnable() {
            public void run() {
                Refresh_HIST_DATA();
            }
          }).start();

но НЕ, когда на Mobile (GPRS), поскольку он убивается примерно через 10 секунд!

Это полу-решение на данный момент, и я попробую решение CommonsWare для более чистого/более устойчивого подхода...

Посмотрим, работает ли новое решение нитей хорошо или просто удача (я тестировал только пару часов)...

Если у кого-то еще есть другое предложение, пожалуйста, разместите его.

Ответ 3

Вместо потока. Вы можете запустить AsyncTask из вашего широковещательного приемника onRecive(). Это не будет блокировать поток пользовательского интерфейса. Я сам делал то же самое в своих проектах, которые имеют одинаковую природу, т.е. Он должен публиковать данные каждые 1 час.

public void onReceive(Context context, Intent intent) {
        // start your Asynctask from here. which will post data in doInBackground() method
}