Android:如何定期发送位置到服务器
我正在运行一个Web服务,允许用户将他们的旅行logging(像Google的MyTracks)作为一个更大的应用程序的一部分。 问题是当用户开始旅程或结束旅程时,很容易将包括坐标和其他项目在内的数据传递给服务器。 作为一个新手,我不知道如何设置一个后台服务,发送位置更新一次(预先确定)一段时间(最less3分钟,最多1小时),直到用户标记行程结束,或直到预设的时间量过去了。
一旦旅程从电话开始,服务器将以手机的轮询周期作为更新之间的间隔来响应。 这部分工作,我可以在手机上显示响应,我的服务器注册用户的操作。 类似地,在紧急旅程请求时,旅行在服务器端closures。
然而,当我尝试从StartTrack Activity中启动一个周期性的跟踪方法,使用requestLocationUpdates(String provider,long minTime,float minDistance,LocationListener listener),其中minTime是服务器的轮询周期,它只是不起作用,米没有得到任何错误。 所以这意味着我在这个时候毫无头绪,以前从未使用过Android。
我在这里看到很多关于使用后台服务处理程序,待处理的意图和其他事情做类似的东西,但我真的不知道如何做到这一点。 我希望用户在更新进行的时候在手机上做其他的事情,所以如果你们能指点我一个教程来展示如何实际编写后台服务(也许这些服务是作为单独的类运行的)或者其他方式这样做,这将是伟大的。
谢谢!
您需要创build一个单独的类,该类是Service
类的一个子类。
服务文档
您的主应用程序应该可以调用startService
和stopService
来启动后台进程。 在上下文类别中还有一些其他有用的调用来pipe理服务:
上下文文档
我最近写了其中一个,并决定离开后台服务运行不是一个好主意。 无论如何,它可能会被操作系统closures,或者可能会被操作系统closures。 我所做的就是使用filter作为引导意图,然后使用警报pipe理器设置一个警报,以便我的应用程序定期重新启动,然后发送数据。 您可以在Android文档中find关于服务和报警pipe理器的更多信息。
首先,我创build了一个广播接收器,当互联网连接打开时,我只需要启动我的服务(我只关心是否有连接 – 您可能也想筛选启动事件)。 发射接收机必须是短暂的,所以只要开始你的服务:
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>
请注意我是如何为自己的闹钟设置一个filter的,这样可以让我closures服务并在服务完成后重新启动服务。
我的显示器服务的顶部看起来像:
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(),所以我的服务只能在没有任何操作的情况下进行,除非由操作系统closures。 由于我是这个应用程序的唯一用户,这并不重要,但对于公共应用程序,这个想法是你设置下一个时间间隔的警报,然后stopSelfclosures。
更新请参阅@juozas关于使用“alarms.setRepeating()”的评论。
我同意Rob Kent,另外我认为可能会在您的BroadcastReceiver中延伸WakefulBroadcastReceiver并使用它的静态方法startWakefulService(android.content.Context context,android.content.Intent intent)
,因为它会保证你的服务不会closures由os。
public class YourReceiver extends WakefulBroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent service = new Intent(context, YourService.class); startWakefulService(context, service); } }
官方文件