Служба Android и повторяющаяся задача, выполняемая в потоках

Я запускаю службу в фоновом режиме, которая считывает местоположение GPS / сети и должна выполнять следующие действия:

Есть несколько вещей, которые я рассмотрел, и я не уверен, правильно понял. Служба работает в том же потоке, что и основное приложение, поэтому отправка местоположения на сервер в том же потоке, что и поток пользовательского интерфейса, может инициировать зависание пользовательского интерфейса, и это плохо. Также я не уверен, что у слушателей GPS / сети есть свои собственные потоки или они используют тот же поток, что и приложение.

Ниже приведен сокращенный код службы, чтобы сделать все более понятным:

public class GPSLoggerService extends Service { @Override public void onCreate() { locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); } @Override public int onStartCommand(Intent intent, int flags, int startId) { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 50, locationListenerNetwork); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 50, locationListenerGps); scheduleTaskExecutor = Executors.newScheduledThreadPool(5); scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() { @Override public void run() { updateLocation(lastLocation); }, 60, 60, TimeUnit.SECONDS); return START_STICKY; } LocationListener locationListenerGps = new LocationListener() { @Override public void onLocationChanged(Location location) { updateLocation(location); } ... } LocationListener locationListenerNetwork = new LocationListener() { @Override public void onLocationChanged(Location location) { updateLocation(location); } ... } private void updateLocation(Location readLocation) { //web service call String response = WebServiceCalls.updateLocation(readLocation); //log data in a local Sqlite database saveLocation(readLocation) } 

Моя главная проблема заключается в том, как обращаться с вызовом updateLocation и иметь его в отдельном потоке из основного потока приложений. РасписаниеTaskExecutor Я считаю, что это не путь. Иногда даже после вызова stopService () служба остается в живых, даже если я скажу TaskExecutor о закрытии. Я не могу найти другое объяснение, по которому служба не останавливается. Итак, чтобы повторить: мне нужно отправить местоположение каждый раз, когда слушатели получают новое место и повторно отправляют его каждые 60 секунд. Я также должен иметь возможность быстро остановить службу с активным отключением потоков.

Как бы вы порекомендовали мне заняться моим делом?

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

    И после получения местоположения из метода onLocationChanged () вы можете использовать асинтез для отправки местоположения в веб-сервис, чтобы он не блокировал ваш пользовательский интерфейс.

    редактировать

    1. Вы можете установить минимальное время и минимальное расстояние, пройденное в методе requestLocationUpdates . Поэтому я не думаю, что вы должны использовать задачу планировщика для отправки местоположения на сервер. Согласно аргументу о минимальном времени и минимальном расстоянии менеджер местоположения проверяет местоположение. Если местоположение изменилось, оно вызовет методLocationChanged () с новым местоположением. Теперь для вашего решения о том, что пользователь остается в одном месте. Вы можете изменить некоторую логику на стороне сервера, как если бы была разница в 1 час между двумя последовательными местоположениями location1 и location2, означает, что пользователь остался 1 час в location1.

    2. Вы можете использовать один класс LocationListener для прослушивания местоположения GPS и NETWORK.

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

    Я бы использовал IntentService и просто использовал AlarmManager для запуска намерений.

    Главным преимуществом этого является то, что нет никакого кода Thread, о котором нужно беспокоиться, поскольку он работает в фоновом режиме

    ОБНОВИТЬ

    Другой интересный подход можно найти в https://stackoverflow.com/a/7709140/808940

    • Служба выполняет тот же процесс, что и основное приложение, а не поток. Также, если вы хотите запустить службу в другом процессе, вы можете использовать тег android: process .

    • Я не уверен, почему вы хотите называть WebService каждые 60 секунд, потому что 60 секунд меньше. Также вы должны пропустить вызов WebService, когда местоположение не изменилось, поскольку для этого требуется сетевое общение, и это дорогостоящая операция.

    • Нет необходимости использовать Исполнителей. Вы должны сохранить количество потоков как можно меньше. Чтобы выполнить задание с определенным интервалом, используйте AlarmManager для доставки намерения в определенное время. Проверьте метод setRepeating () для установки будильника.

    • Другое дело, вы должны стараться избегать выполнения какой-либо задачи в Listener. Потому что есть время в 10 секунд, которое позволяет система, прежде чем рассматривать приемника / слушателя, который будет заблокирован, и кандидата, которого нужно убить. Вы должны использовать обработчик для выполнения задач в фоновом потоке (т. Е. Всякий раз, когда вы получаете обновление от слушателя, добавьте сообщение в очередь обработчика, и оно будет выбрано, когда поток Handler будет бесплатным).

    Вы должны использовать AsynchTask:

     public class RefreshTask extends AsyncTask<Integer, Void, Integer> { /** * The system calls this to perform work in a worker thread and delivers * it the parameters given to AsyncTask.execute() */ public RefreshTask() { } protected Integer doInBackground(Integer... millis) { try{ int waitTime = 0; while(waitTime<60000){ Thread.sleep(100); waitTime += 100; } //update location here }catch(InterruptedException e){ } return 1; } /** * The system calls this to perform work in the UI thread and delivers * the result from doInBackground() */ protected void onPostExecute(Integer result) { new RefreshTask.execute(); } } в public class RefreshTask extends AsyncTask<Integer, Void, Integer> { /** * The system calls this to perform work in a worker thread and delivers * it the parameters given to AsyncTask.execute() */ public RefreshTask() { } protected Integer doInBackground(Integer... millis) { try{ int waitTime = 0; while(waitTime<60000){ Thread.sleep(100); waitTime += 100; } //update location here }catch(InterruptedException e){ } return 1; } /** * The system calls this to perform work in the UI thread and delivers * the result from doInBackground() */ protected void onPostExecute(Integer result) { new RefreshTask.execute(); } }