5

我正在后台运行一项读取 GPS/网络位置的服务,需要执行以下操作:

  • 在后台运行而不会在应用程序重新启动时中断,并尽可能保持其活着而不会被杀死(这在 Merlin 的评论的帮助下得到了解决)

  • 在收到新位置时,调用 Web 服务并发送读取的位置

  • 每 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 调用并将其放在与主应用程序线程不同的线程中。scheduleTaskExecutor 我相信这不是要走的路。有时,即使在我调用 stopService() 之后,服务仍然存在,即使我告诉 TaskExecutor 关闭。我找不到服务没有停止的其他解释。回顾一下:我需要在每次听众收到新位置时发送位置,并每 60 秒重新发送一次。我还需要能够通过取消活动线程来快速停止服务。

你会建议我如何处理我的案子?

4

4 回答 4

4

我会使用 IntentService 并仅使用 AlarmManager 来触发意图。

这样做的主要优点是无需担心线程代码,因为它在后台工作

更新

另一种有趣的方法可以在https://stackoverflow.com/a/7709140/808940中找到

于 2012-07-09T20:50:03.990 回答
2
  • 该服务与主应用程序运行相同的进程,而不是线程。此外,如果您想在另一个进程中运行服务,则可以使用android:process标签。

  • 我不确定你为什么要每 60 秒调用一次 WebService,因为 60 秒太少了。此外,当位置未更改时,您应该跳过调用 WebService,因为它需要网络通信并且这是一项昂贵的操作。

  • 无需使用执行器。您应该尽可能减少线程数。要在特定时间间隔执行任务,请使用 AlarmManager 在特定时间传递意图。检查setRepeating()方法来设置警报。

  • 另一件事是,您应该尽量避免在 Listener 中执行任何任务。因为在考虑阻止接收者/侦听者和杀死候选人之前,系统允许有 10 秒的超时。您应该使用Handler在后台线程中执行任务(即,每当您从侦听器接收到更新时,将消息添加到 Handler 队列,当 Handler 线程空闲时将被选中)。

于 2012-07-12T16:16:33.967 回答
1

为了防止您的服务被破坏,您可以将您的服务作为前台服务启动。

从 onLocationChanged() 方法获取位置后,您可以使用asynctask将位置发送到 Web 服务,这样它就不会阻塞您的 UI。

编辑

  1. 您可以在requestLocationUpdates方法中设置最短时间和最短距离。因此,我认为您不应该使用调度程序任务将位置发送到服务器。根据关于最小时间和最小距离的参数,位置管理器将检查位置。如果位置发生更改,那么它将使用新位置调用 onLocationChanged() 方法。现在,您关于用户的解决方案保持不变。您可以将一些逻辑更改为服务器端,例如两个连续位置 location1 和 location2 之间是否相差 1 小时意味着用户在 location1 停留了 1 小时。

  2. 您可以使用单个 LocationListener 类来监听 GPS 和 NETWORK 位置。

  3. 当您在 onLocationChanged() 方法中获取位置时,您可以使用异步任务发送该位置。
  4. 获得位置后,您可以将该位置保存在首选项或数据库中,以检查 GPS 和网络提供商向您发送相同位置的天气,因此如果您要跟踪,则可以保存您的 webAPI 调用,这样您就可以节省一部分电池电量。
于 2012-07-10T04:45:51.607 回答
-1

你应该使用异步任务:

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();
    }


}
于 2012-07-15T23:30:42.713 回答