handler.postDelayed против AlarmManager против - PullRequest
1 голос
/ 31 марта 2011

У меня небольшая проблема в одном из моих приложений.Он использует BroadCastReceiver, чтобы определить, когда заканчивается вызов, а затем выполняет некоторые второстепенные служебные задачи.Они должны быть отложены на несколько секунд, чтобы позволить пользователю увидеть некоторые данные и убедиться, что журнал вызовов обновлен.В настоящее время я использую handler.postDelayed() для этой цели:

public class CallEndReceiver extends BroadcastReceiver {

@Override
public void onReceive(final Context context, final Intent intent) {
    if (DebugFlags.LOG_OUTGOING)
        Log.v("CallState changed "
                + intent.getStringExtra(TelephonyManager.EXTRA_STATE));
    if (intent.getStringExtra(TelephonyManager.EXTRA_STATE)
            .equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)) {
        SharedPreferences prefs = Utils.getPreferences(context);
        if (prefs.getBoolean("auto_cancel_notification", true)) {
            if (DebugFlags.LOG_OUTGOING)
                Log.v("Posting Handler to remove Notification ");
            final Handler mHandler = new Handler();
             final Runnable mCancelNotification = new Runnable() {
                   public void run() {
                        NotificationManager notificationMgr = (NotificationManager) context
                        .getSystemService(Service.NOTIFICATION_SERVICE);
                notificationMgr.cancel(12443);
                if (DebugFlags.LOG_OUTGOING)
                    Log.v("Removing Notification ");
                   }
                };
                mHandler.postDelayed(mCancelNotification, 4000);


        }
        final Handler updateHandler = new Handler();
         final Runnable mUpdate = new Runnable() {
               public void run() {
        if (DebugFlags.LOG_OUTGOING)
            Log.v("Starting updateService");
        Intent newBackgroundService = new Intent(context,
                CallLogUpdateService.class);
        context.startService(newBackgroundService);
               }
               };
               updateHandler.postDelayed(mUpdate, 5000);

        if (DebugFlags.TRACE_OUTGOING)
            Debug.stopMethodTracing();
        try
        {
        // Stopping old Service
        Intent backgroundService = new Intent(context,
                NetworkCheckService.class);
        context.stopService(backgroundService);
        context.unregisterReceiver(this);
        }
        catch(Exception e)
        {
            Log.e("Fehler beim Entfernen des Receivers", e);
        }
    }

}

}

Теперь у меня проблема, что эта установка работает примерно в 90% случаев.Примерно в 10% случаев уведомление не удаляется.Я подозреваю, что поток умирает до того, как очередь сообщений обработает сообщение / runnable.

Сейчас я думаю об альтернативах postDelayed(), и один из моих вариантов, очевидно, - AlarmManager.Однако я не уверен насчет влияния на производительность (или ресурсов, которые он использует).

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

Спасибо

Ответы [ 4 ]

4 голосов
/ 31 марта 2011

В настоящее время я использую handler.postDelayed () для этой цели:

Это не очень хорошая идея, если предположить, что BroadcastReceiver запускается фильтром в манифесте.

Теперь у меня проблема, что эта установка работает примерно в 90% случаев.Примерно в 10% случаев уведомление не удаляется.Я подозреваю, что поток умирает до того, как очередь сообщений обрабатывает сообщение / runnable.

Точнее, процесс завершается, все забирая с собой.

I 'Теперь я думаю об альтернативах postDelayed (), и один из моих вариантов, очевидно, AlarmManager.Однако я не уверен насчет влияния на производительность (или ресурсов, которые он использует).

Это не так уж плохо.Другая возможность состоит в том, чтобы выполнить вашу отложенную работу в IntentService - вызванном вызовом startService() - и оставить его в фоновом потоке на пару секунд.

2 голосов
/ 25 февраля 2017

Давайте попробуем новый способ сделать это. Использование RxJava. Намного проще создавать прототипы и проще управлять множеством потоков, если вы хотите когда-либо запускать сотни таких отложенных задач одновременно, последовательно, в сочетании с асинхронными задачами, связанными с синхронными цепными асинхронными вызовами и т. Д.

Во-первых, настройте подписчика. Помните, new на Subscriber следует выполнять только один раз, чтобы избежать утечек памяти.

// Set up a subscriber once
private Subscuber<Long> delaySubscriber = new Subscuber<Long> () {
    @Override
    public void onCompleted() {
        //Wrap up things as onCompleted is called once onNext() is over
    }
    @Override
    public void onError(Throwable e) {
        //Keep an eye open for this. If onCompleted is not called, it means onError has been called. Make sure to override this method
    }
    @Override
    public void onNext(Long aLong) {
        // aLong will be from 0 to 1000
        // Yuor code logic goes here

        // If you want to run this code just once, just add a counter and call onComplete when the counter runs the first time

    }
} 

Фрагмент ниже просто выдаст 1 в onNext () подписчика. Обратите внимание, что это делается в вычислительном пуле потоков, созданном и управляемом библиотекой RxJava.

//Now when you want to start running your piece of cade, define an Observable interval that'll emit every second
private Observable<Long> runThisAfterDelay = Observable.just(1).delay(1000, TimeUnit.MILLISECONDS, Schedulers.computation());
// Subscribe to begin the emissions.
runThisAfterDelay.subscribe(delaySubscriber);

Если вы хотите запускать код, скажем, каждую секунду, то вы можете сделать это:

private Observable<Long> runThisOnInterval = Observable.interval(1000, TimeUnit.MILLISECONDS, Schedulers.computation());
0 голосов
/ 14 июля 2016

AlarmManager, кажется, не очень хорошо работает в течение коротких промежутков времени, например, 10 секунд, и согласно пользовательским отчетам поведение сильно зависит от прошивки.* в моем сервисе.

При создании Handler обязательно создайте его внутри класса Service, а не внутри BroadcastReceiver, поскольку в последнем случае вы получите Can't create Handler inside thread that has not called Looper.prepare()

public class NLService extends NotificationListenerService {
    private NLServiceReceiver nlservicereciver;
    Handler delayUpdateHandler = new Handler();
    private Runnable runBroadcastUpdate;

    public void triggerViewUpdate() {
        /* Accumulate view updates for faster, resource saving operation.
        Delay the update by some milliseconds.
        And if there was pending update, remove it and plan new update.
         */
        if (runBroadcastUpdate != null) {
            delayUpdateHandler.removeCallbacks(runBroadcastUpdate);
        }
        runBroadcastUpdate = new Runnable() {
            public void run() {
                // Do the work here; execution is delayed
            }
        };
        delayUpdateHandler.postDelayed(runBroadcastUpdate, 300);
    }

    class NLServiceReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            triggerViewUpdate();
        }
    }

}
0 голосов
/ 26 марта 2012

В дополнение к первому ответу вы можете рассмотреть, что написано в документации API для метода onReceive:

[...]обычно вызывается в основном потоке его процесса, , поэтому вы никогда не должны выполнять в нем длительные операции [...]

Так что, как правило, это неХорошая идея запустить что-то, что ждет пару раз в onReceive (хотя, в вашем случае это меньше, чем предел в 10 с).

У меня была похожая ошибка BroadcastReceiver.Я не мог обработать свои результаты, даже если мне onReceive позвонили именно с тем, что я ожидал.Казалось, что поток, в котором работал BroadastReceiver, был убит до того, как моя обработка результатов могла закончиться.Моим решением было создать новую нить для выполнения всей обработки.

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