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

Android: как периодически отправлять местоположение на сервер

Я запускаю веб-службу, которая позволяет пользователям записывать свои поездки (вроде Google MyTracks) как часть более крупного приложения. Дело в том, что легко передавать данные, в том числе коорды и другие предметы, на сервер, когда пользователь начинает поездку или заканчивает ее. Являясь новичком, я не знаю, как настроить фоновый сервис, который отправляет обновления местоположения раз в каждый (заранее определенный) период (мин. 3 минуты, максимум 1 час), пока пользователь не запустит окончание поездки или пока заданное количество времени.

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

Однако, когда я попытался запустить периодический метод отслеживания изнутри StartTrack Activity, используя requestLocationUpdates (поставщик строк, long minTime, float minDistance, ListListener listener), где minTime - период опроса с сервера, он просто не работает, и я не получаю никаких ошибок. Поэтому это означает, что я не знаю, на данный момент, никогда не использовал Android раньше.

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

Спасибо!

4b9b3361

Ответ 1

Вам нужно создать отдельный класс, который является подклассом класса Service.

Документация по сервису

Ваше основное приложение должно вызвать startService и stopService, чтобы запустить фоновый процесс. Кроме того, есть некоторые другие полезные вызовы в классе контекста для управления службой:

Контекстная документация

Ответ 2

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

Сначала я создал широковещательный приемник, который просто запускает мой сервис при открытии интернет-соединения (меня интересует только соединение с ним - вы можете также фильтровать событие загрузки). Приемник запуска должен быть недолговечным, поэтому просто запустите свой сервис:

public class LaunchReceiver extends BroadcastReceiver {

    public static final String ACTION_PULSE_SERVER_ALARM = 
            "com.proofbydesign.homeboy.ACTION_PULSE_SERVER_ALARM";

    @Override
    public void onReceive(Context context, Intent intent) {
        AppGlobal.logDebug("OnReceive for " + intent.getAction());
        AppGlobal.logDebug(intent.getExtras().toString());
        Intent serviceIntent = new Intent(AppGlobal.getContext(),
                MonitorService.class);
        AppGlobal.getContext().startService(serviceIntent);
    }
}

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

<receiver
    android:name="LaunchReceiver"
    android:label="@string/app_name" >
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
    <intent-filter>
        <action android:name="com.proofbydesign.homeboy.ACTION_PULSE_SERVER_ALARM" />
    </intent-filter>
</receiver>

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

Верхняя часть службы моего монитора выглядит так:

public class MonitorService extends Service {

    private LoggerLoadTask mTask;
    private String mPulseUrl;
    private HomeBoySettings settings;
    private DataFile dataFile;
    private AlarmManager alarms;
    private PendingIntent alarmIntent;
    private ConnectivityManager cnnxManager;

    @Override
    public void onCreate() {
        super.onCreate();
        cnnxManager = (ConnectivityManager) 
                getSystemService(Context.CONNECTIVITY_SERVICE);
        alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent intentOnAlarm = new Intent(
                LaunchReceiver.ACTION_PULSE_SERVER_ALARM);
        alarmIntent = PendingIntent.getBroadcast(this, 0, intentOnAlarm, 0);
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        // reload our data
        if (mPulseUrl == null) {
            mPulseUrl = getString(R.string.urlPulse);
        }
        AppGlobal.logDebug("Monitor service OnStart.");
        executeLogger();
    }

executeLogger запускает asyncTask, что, вероятно, я чрезмерно осторожно (это было только мое третье приложение для Android). AsyncTask захватывает данные GPS, отправляет их в Интернет и, наконец, устанавливает следующий сигнал:

private void executeLogger() {
    if (mTask != null
        && mTask.getStatus() != LoggerLoadTask.Status.FINISHED) {
        return;
    }
    mTask = (LoggerLoadTask) new LoggerLoadTask().execute();
}

private class LoggerLoadTask extends AsyncTask<Void, Void, Void> {

    // TODO: create two base service urls, one for debugging and one for live.
    @Override
    protected Void doInBackground(Void... arg0) {
        try {
            // if we have no data connection, no point in proceeding.
            NetworkInfo ni = cnnxManager.getActiveNetworkInfo();
            if (ni == null || !ni.isAvailable() || !ni.isConnected()) {
                AppGlobal
                        .logWarning("No usable network. Skipping pulse action.");
                return null;
            }
            // / grab and log data
        } catch (Exception e) {
            AppGlobal.logError(
                    "Unknown error in background pulse task. Error: '%s'.",
                    e, e.getMessage());
        } finally {
            // always set the next wakeup alarm.
            int interval;
            if (settings == null
                || settings.getPulseIntervalSeconds() == -1) {
                interval = Integer
                        .parseInt(getString(R.string.pulseIntervalSeconds));
            } else {
                interval = settings.getPulseIntervalSeconds();
            }
            long timeToAlarm = SystemClock.elapsedRealtime() + interval
                * 1000;
            alarms.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, timeToAlarm,
                    alarmIntent);
        }
        return null;
    }
}

Я замечаю, что после настройки будильника я не вызываю stopSelf(), поэтому моя служба будет сидеть без дела, если не выключится оператором sys. Поскольку я единственный пользователь этого приложения, это не имеет значения, но для публичного приложения, идея заключается в том, что вы устанавливаете будильник на следующий интервал, а затем останавливаетесь для закрытия.

Обновление См. комментарий от @juozas об использовании 'alarms.setRepeating()'.

Ответ 3

Я согласен с Робом Кентом, и в дополнение, я думаю, может быть, что Beter расширяет WakefulBroadcastReceiver в вашем BroadcastReceiver и использует его статический метод startWakefulService(android.content.Context context,android.content.Intent intent), потому что он гарантирует, что ваш сервис не будет закрыт os.

public class YourReceiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

        Intent service = new Intent(context, YourService.class);
        startWakefulService(context, service);
    }
}

Официальная документация