Android:如何定期向服务器发送位置信息

Android:如何定期向服务器发送位置信息,android,Android,我正在运行一个Web服务,允许用户记录他们的旅行(有点像谷歌的MyTracks),作为更大应用程序的一部分。问题是,当用户开始或结束旅行时,向服务器传递数据(包括coords和其他项目)很容易。作为一个新手,我不知道如何设置一个后台服务,在用户标记行程结束或预设时间过去之前,每隔一段(预先确定的)时间(最短3分钟,最长1小时)发送一次位置更新 从手机开始旅行后,服务器会以轮询周期响应,以供手机用作更新间隔。这一部分可以工作,因为我可以在手机上显示响应,我的服务器可以注册用户的操作。类似地,根据关

我正在运行一个Web服务,允许用户记录他们的旅行(有点像谷歌的MyTracks),作为更大应用程序的一部分。问题是,当用户开始或结束旅行时,向服务器传递数据(包括coords和其他项目)很容易。作为一个新手,我不知道如何设置一个后台服务,在用户标记行程结束或预设时间过去之前,每隔一段(预先确定的)时间(最短3分钟,最长1小时)发送一次位置更新

从手机开始旅行后,服务器会以轮询周期响应,以供手机用作更新间隔。这一部分可以工作,因为我可以在手机上显示响应,我的服务器可以注册用户的操作。类似地,根据关闭跳闸请求,跳闸在服务器端关闭

但是,当我尝试从StartTrack活动内部使用requestLocationUpdates(字符串提供程序、long minTime、float minDistance、LocationListener listener)启动定期跟踪方法时,minTime是来自服务器的轮询周期,但它不起作用,我没有收到任何错误。所以这意味着我在这一点上一无所知,以前从未使用过Android


我在这里看到过很多关于使用后台服务处理程序、未决意图和其他类似事情的帖子,但我真的不知道怎么做。我希望用户在更新过程中在手机上做其他事情,所以如果你们能给我指一个教程,说明如何实际编写后台服务(可能这些服务作为单独的类运行?)或其他方法,那太好了。

您需要创建一个单独的类,它是
服务的子类

您的主应用程序应该可以调用
startService
stopService
来启动后台进程。上下文类中还有一些其他有用的调用来管理服务:


我最近写了一篇文章,认为让后台服务运行不是一个好主意。无论如何,它可能会被操作系统关闭,也可能会。我所做的是使用一个用于引导目的的过滤器,然后使用alarm manager设置一个警报,以便定期重新启动我的应用程序,然后它发送数据。你可以在Android文档中找到关于服务和报警管理器的好信息

首先,我创建了一个广播接收器,它只在打开internet连接时启动我的服务(我只对有连接的情况感兴趣-您可能还想过滤启动事件)。启动接收器必须是短期的,因此只需启动您的服务:

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>
executeLogger启动了一个异步任务,这可能是因为我过于谨慎(这只是我的第三个Android应用程序)。asyncTask获取GPS数据,将其发送到internet,并最终设置下一个警报:

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;
    }
}
private void executeLogger(){
如果(mTask!=null
&&mTask.getStatus()!=LoggerLoadTask.Status.FINISHED){
返回;
}
mTask=(LoggerLoadTask)新建LoggerLoadTask().execute();
}
私有类LoggerLoadTask扩展了AsyncTask{
//TODO:创建两个基本服务URL,一个用于调试,另一个用于live。
@凌驾
受保护的Void doInBackground(Void…arg0){
试一试{
//如果我们没有数据连接,就没有继续的必要。
NetworkInfo ni=cnnxManager.getActiveNetworkInfo();
如果(ni==null | | |!ni.isAvailable()| |!ni.isConnected()){
AppGlobal
.logWarning(“无可用网络。跳过脉冲动作”);
返回null;
}
///GRAP和日志数据
}捕获(例外e){
AppGlobal.logError(
“后台脉冲任务中存在未知错误。错误:“%s”。”,
e、 e.getMessage());
}最后{
//始终设置下一个唤醒警报。
整数区间;
如果(设置==null
||settings.getPulseIntervalSeconds()=-1){
间隔=整数
.parseInt(getString(R.string.pulseIntervalSeconds));
}否则{
间隔=设置。GetPulseSIntervalSeconds();
}
long-timeToAlarm=SystemClock.elapsedRealtime()+间隔
* 1000;
报警设置(AlarmManager.Appeased\u REALTIME\u WAKEUP,timeToAlarm,
报警意图);
}
返回null;
}
}
我注意到在设置报警后我没有调用stopSelf(),因此我的服务将无所事事,除非被op sys关闭。因为我是这个应用程序的唯一用户,这并不重要,但是对于一个公共应用程序,你的想法是为下一个间隔设置警报,然后停止自我关闭


更新查看@juozas关于使用“alarms.setRepeating()”的评论。

我同意Rob Kent的观点,另外,我认为最好在您的BroadcastReceiver中扩展WakefulBroadcastReceiver,并使用其静态方法
startWakefulService(android.content.Context上下文,android.content.Intent Intent)
,因为它保证你的服务不会被操作系统关闭

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

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

非常感谢。我已经能够构建服务,启动和停止它。我现在必须确保系统不会杀死它,并且在需要时调用它。请记住,操作系统会在它认为合适的时候定期停止(并重新启动)您的服务:jscharf,我如何确保服务被保证定期调用,并且只在那时运行,直到用户执行特定的操作来停止调用?我希望使用一个警报,并仔细阅读有关如何使用它们的文档…您可以让警报服务在某个定期时间向您的服务发送意图,也可以生成一个警报
public class YourReceiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

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