Android:如何定期向服务器发送位置信息
我正在运行一个Web服务,允许用户记录他们的旅行(有点像谷歌的MyTracks),作为更大应用程序的一部分。问题是,当用户开始或结束旅行时,向服务器传递数据(包括coords和其他项目)很容易。作为一个新手,我不知道如何设置一个后台服务,在用户标记行程结束或预设时间过去之前,每隔一段(预先确定的)时间(最短3分钟,最长1小时)发送一次位置更新 从手机开始旅行后,服务器会以轮询周期响应,以供手机用作更新间隔。这一部分可以工作,因为我可以在手机上显示响应,我的服务器可以注册用户的操作。类似地,根据关闭跳闸请求,跳闸在服务器端关闭 但是,当我尝试从StartTrack活动内部使用requestLocationUpdates(字符串提供程序、long minTime、float minDistance、LocationListener listener)启动定期跟踪方法时,minTime是来自服务器的轮询周期,但它不起作用,我没有收到任何错误。所以这意味着我在这一点上一无所知,以前从未使用过AndroidAndroid:如何定期向服务器发送位置信息,android,Android,我正在运行一个Web服务,允许用户记录他们的旅行(有点像谷歌的MyTracks),作为更大应用程序的一部分。问题是,当用户开始或结束旅行时,向服务器传递数据(包括coords和其他项目)很容易。作为一个新手,我不知道如何设置一个后台服务,在用户标记行程结束或预设时间过去之前,每隔一段(预先确定的)时间(最短3分钟,最长1小时)发送一次位置更新 从手机开始旅行后,服务器会以轮询周期响应,以供手机用作更新间隔。这一部分可以工作,因为我可以在手机上显示响应,我的服务器可以注册用户的操作。类似地,根据关
我在这里看到过很多关于使用后台服务处理程序、未决意图和其他类似事情的帖子,但我真的不知道怎么做。我希望用户在更新过程中在手机上做其他事情,所以如果你们能给我指一个教程,说明如何实际编写后台服务(可能这些服务作为单独的类运行?)或其他方法,那太好了。您需要创建一个单独的类,它是
服务的子类
您的主应用程序应该可以调用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);
}
}