0

这是我现在要做的:

  1. 我有一个在后台运行并读取用户位置的服务。每次读取有效位置(有一些参数,如距离和时间)时,都会启动 IntentService 以将该位置发送到 Web 服务器

  2. 使用跟踪服务的应用程序也有一些网络调用,具体取决于用户按下的选项。现在,应用程序只是在 asynctask 中调用 Web 服务。

一些代码:位置服务触发 IntentService,每次收到一个好的位置,像这样:

Intent intentService = new Intent(LocationLoggerService.this, LocationManagerIntentService.class);
intentService.putExtra(Constants.MESSAGE_LOCATION, readLocation);
startService(intentService);

意图服务处理意图:

@Override
protected void onHandleIntent(Intent intent) {
     LocationInfo location = intent.getExtras().getParcelable(Constants.MESSAGE_LOCATION);
   .... //Do the web call and broadcast result to app
}

以下是我需要进行的更改:

  1. IntentService 和应用程序不能同时调用 Web 服务器。由于现在已经实施,这是不可能的,因为它们是独立的。我正在考虑通过为所有这些调用创建意图,将应用程序中的所有 Web 调用传递给 IntentService。这行得通吗?如果有位置网络发送,来自应用程序调用的新意图将被放入队列并在当前调用之后立即执行?

  2. 如果由于网络速度低而队列中有多个位置发送,则应用调用需要放在队列前面,而不是等待所有现有意图完成,仅等待当前意图。有没有办法将意图放在队列之上?

谢谢你。

后期编辑:

这是我所做的更改。

  1. 创建自定义意图服务
public abstract class PriorityIntentService extends Service {
      private final AtomicInteger     intentsCount    = new AtomicInteger();

  protected void intentFinished() {
      intentsCount.decrementAndGet();
  }

  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }

      public final boolean sendPriorityMessage(Message msg) {

          intentsCount.incrementAndGet();

          int priority = msg.arg2;

          if (priority == 0) {
              return sendMessageAtFrontOfQueue(msg);
          } else {
              return sendMessage(msg);
          }

      }

      @Override
      public void handleMessage(Message msg) {
          onHandleIntent((Intent) msg.obj);

          if (intentsCount.get() == 0) {
              // stopSelf(msg.arg1);
              stopSelf();
          }
      }
  }


  @Override
  public void onStart(Intent intent, int startId) {

      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      msg.obj = intent;

      if (intent.getExtras().getInt(Constants.MESSAGE_PRIORITY) == 0) {
          msg.arg2 = 0;
      } else {
          msg.arg2 = 1;
      }

      mServiceHandler.sendPriorityMessage(msg);
      // mServiceHandler.sendMessage(msg);
  }
}
  1. 和其他服务:
public class LocationManagerIntentService extends PriorityIntentService {

    @Override
      protected void onHandleIntent(Intent intent) {

      intentFinished();
      }
}
4

1 回答 1

3

由于构建方式,您想要做的事情是不可能的IntentService,但是,IntentService这是一个非常简单的代码并且是开源的,因此您只需进行一些修改即可创建自己的版本。

原始代码在这里

在该onCreate()方法中,您可以看到在哪里Service创建了 aHandlerThread和 aHandler来调度所有onHandleIntent调用。

所以你所要做的就是:

  • 创建一个单例HandlerThreadHandler供您的整个应用程序使用。每次网络调用还是CustomIntentService应该调用这个单Handler。这是第 1 部分。您只是强制所有网络调用永远不会同时发生。

  • 现在您已经通过同一个 Thread 和 Handler 进行了所有调用,只需调用Handler.postAtFrontOfQueue来确定某些执行的优先级即可。

快乐编码。

编辑:

新编辑:

它不执行的原因在这里:

stopSelf(msg.arg1);

一旦所有消息被执行,这将停止服务,检查文档

如果最近启动的时间是 ,则停止服务startId。这与调用stopService(Intent)此特定服务相同,但允许您安全地避免在您尚未在onStart(Intent, int).

请注意调用此函数的顺序。如果您在为以前收到的 ID 调用此函数之前使用最近收到的 ID 调用此函数,则无论如何都会立即停止服务。如果您最终可能会乱序处理 ID(例如通过在单独的线程上分派它们),那么您有责任按照收到它们的相同顺序停止它们。

因此,您必须找到一种不同的方法来检查所有消息是否在完成之前都已执行。可能是AtomicInt计算队列中的消息数量,或者是保存startId.

于 2015-02-27T12:10:32.143 回答