我正在后台运行一个读取GPS /网络位置的服务,需要执行以下操作:
在后台运行,不会因应用程序重启而中断,并尽可能保持活着而不会被杀死(这可以通过Merlin的评论帮助解决)
在收到的新位置,调用网络服务并发送阅读位置
每60秒运行一次重复任务,并将最后一个位置重新发送到Web服务。这将有助于用户保持在相同的位置。
我考虑过一些事情,我不确定我是否理解正确。该服务在与主应用程序相同的线程中运行,因此在与UI线程相同的线程上将位置发送到服务器可能会触发UI冻结,这并不好。此外,我不确定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调用并将其放在与主app线程不同的线程中。 scheduleTaskExecutor我相信它不是要走的路。有时候,即使我告诉TaskExecutor关闭了,即使在我调用stopService()之后服务仍然存活。我找不到服务没有停止的另一种解释。 所以回顾一下:每次听众收到一个新位置并每隔60秒重新发送一次,我需要发送该位置。我还需要能够在活动线程取消的情况下快速停止服务。
你怎么建议我处理我的案子?
答案 0 :(得分:4)
我使用IntentService并使用AlarmManager来触发意图。
这样做的主要优点是没有线程代码可以担心,因为它在后台工作
<强>更新强>
另一种有趣的方法可以在https://stackoverflow.com/a/7709140/808940
中找到答案 1 :(得分:2)
服务运行与主应用程序相同的进程,而不是线程。此外,如果您想在其他流程中运行服务,则可以使用android:process代码。
我不确定你为什么要每60秒调用一次WebService,因为60秒太少了。此外,您应该在位置未更改时跳过调用WebService,因为它需要网络通信,而且操作成本很高。
无需使用执行程序。您应该尽可能减少线程数。要以特定间隔执行任务,请使用AlarmManager在特定时间传递意图。检查setRepeating()方法以设置闹钟。
另一件事是,您应该尽量避免在Listener中执行任何任务。因为在考虑接收器/侦听器被阻挡以及被杀死的候选者之前系统允许有10秒的timeout。您应该使用Handler在后台线程中执行任务(即,每当您从侦听器接收更新时,向Handler队列添加一条消息,当Handler线程空闲时它将被选中)。
答案 2 :(得分:1)
为防止您的服务遭到破坏,您可以foreground service启动服务。
从onLocationChanged()方法获取位置后,您可以使用asynctask向Web服务发送位置,以便它不会阻止您的用户界面。
修改强>
您可以在 requestLocationUpdates 方法中设置最短时间和最短距离。所以我认为您不应该使用调度程序任务将位置发送到服务器。根据关于最小时间和最小距离的论点,位置经理将检查位置。如果位置已更改,则会使用新位置调用onLocationChanged()方法。 现在为您提供关于用户停留在同一位置的解决方案。您可以将一些逻辑更改为服务器端,如果两个连续位置之间存在1小时差异location1和location2表示用户在location1停留了1小时。
您可以使用单个LocationListener类来收听GPS和NETWORK位置。
答案 3 :(得分:-1)
你应该使用AsyncTask:
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();
}
}