在 IntentService 中对意图进行优先级排序

Prioritize intents in IntentService

这是我现在所做的:

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

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

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

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

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和app不能同时调用web server。由于现在已经实施,这是不可能的,因为它们是独立行动的。我正在考虑通过为所有网络调用创建意图,将所有网络调用从应用程序传递到 IntentService。这行得通吗?如果有位置网络发送,来自应用程序调用的新意图将被放入队列并在当前调用后立即执行?

  2. 如果因为网速低,队列中有多个location发送,app调用,需要放在队列前面,不等待所有已有的intent完成,只针对当前一。有没有办法将意图放在队列顶部?

谢谢。

稍后编辑:

这是我所做的更改。

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

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

原码为here.

onCreate() 方法中,您可以看到 Service 在哪里创建一个 HandlerThread 和一个 Handler 来分派所有 onHandleIntent 调用。

所以你所要做的就是:

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

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

编码愉快。

编辑:

新编辑:

它没有执行的原因在这里:

stopSelf(msg.arg1);

一旦所有消息都被执行,这将停止服务,检查the docs

Stop the service if the most recent time it was started was startId. This is the same as calling stopService(Intent) for this particular service but allows you to safely avoid stopping if there is a start request from a client that you haven't yet seen in onStart(Intent, int).

Be careful about ordering of your calls to this function. If you call this function with the most-recently received ID before you have called it for previously received IDs, the service will be immediately stopped anyway. If you may end up processing IDs out of order (such as by dispatching them on separate threads), then you are responsible for stopping them in the same order you received them.

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

的映射