Android — Вызов системной службы с фиксированными интервалами из другой службы

#android #multithreading #service #broadcastreceiver #android-context

#Android #многопоточность #Обслуживание #broadcastreceiver #android-контекст

Вопрос:

Как следует из вопроса, мне интересно, как я мог бы написать поток, который вызывал бы системную службу, а затем подождать определенное количество времени, прежде чем вызывать функцию указанной системной службы, которая вызывает обратный вызов onReceive из зарегистрированного BroadcastReceiver .

Другими словами, я пытаюсь вызвать службу сканирования Wi-Fi (регистрируясь BroadcastReceiver в IntentFilters ) в моей пользовательской службе, чтобы я мог получить доступ к текущему SSID. Я знаю, что я в конечном итоге буду делать с полученными данными, которые не имеют отношения к этому вопросу. Однако мне нужно будет подождать определенное количество времени, прежде чем startScan снова вызывать внутри onReceive , и именно здесь я пытаюсь определить наилучший курс действий.

Мне удалось попробовать вызвать сканер wifi таким образом в моем потоке:

     private Object _lock = new Object();

    private final long SLEEP_TIME = 15000; //Scan every 15 secs
    private final long WIFI_SCAN_TIMEOUT = 60000; //One minute timeout for getting called back, otherwise, initiate a new scan.

   @Override
    public void run() {
        while(running){
            //Start a new scan;
            wifiSearchComplete = false;
            _wifiMan.startScan();
            while(!wifiSearchComplete){
                synchronized(_lock){
                    try{
                        _lock.wait(WIFI_SCAN_TIMEOUT);
                    } catch (InterruptedException ie){
                         Log.d(TAG, TAG ".run() caught "   ie.getMessage()  " when trying to sleep for "   (WIFI_SCAN_TIMEOUT/1000)  "secs.");
                         Thread.currentThread().interrupt();
                    }
                }
                if(!wifiSearchComplete){
                    synchronized(_lock){
                        //Try scanning again since we didn't get called back at all;
                        _lock.notify();
                    }
                }
            }
        }
    }

    public boolean isRunning(){
        return running;
    }

    public void stop(){
        synchronized(_lock){
            running = false;
            //unregister receivers and cleanup
            _lock.notify();
        }
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        synchronized(_lock){
               wifiSearchComplete = true;
               //iterate through our SSID's
                try{
                    _lock.wait(SLEEP_TIME);
                } catch (InterruptedException ie){
                     Log.d(TAG, TAG ".onReceive() caught "   ie.getMessage()  " when trying to sleep for "   (SLEEP_TIME/1000)  "secs.");
                     Thread.currentThread().interrupt();
                }
                _lock.notify();
            }
    }
  

Однако, несмотря на то, что он ожидает каждые 15 секунд перед повторным сканированием, при попытке завершить мою тестовую активность (вызов onDestroy ) он блокирует основной поток на время ожидания, прежде чем он отключит службу. Другими словами, является ли это подходящим способом попытаться выполнить то, что я хочу сделать, без блокировки, или я должен просто создать BroadcastReceiver и вызвать Thread.sleep в конце onReceive перед вызовом запуска нового сканирования?

Ответ №1:

Вы должны реализовать IntentService. В вашей реализации переопределите onHandleIntent () для сканирования Wi-Fi.

Затем используйте AlarmManager, чтобы запланировать отправку Intent в ваш IntentService через некоторый интервал. Придумайте свое собственное имя действия: «diago.intent.scan_wifi» или что-то в этом роде. Если вы используете один из «неточных повторяющихся интервалов» (например, 15 минут), то ОС Android запланирует все остальные службы одновременно, чтобы свести к минимуму количество раз, когда телефон должен выходить из спящего режима.

Наконец, реализуйте BroadcastReceiver для ответа на ACTION_BOOT_COMPLETED и вызовите свой код, чтобы запланировать AlarmManager. Это запустит вашу службу при загрузке.

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

Комментарии:

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