【问题标题】:Prioritize intents in IntentServiceIntentService 中的意图优先级
【发布时间】:2015-02-27 11:09:21
【问题描述】:

这是我现在要做的:

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

  2. 使用跟踪服务的应用程序也有一些网络调用,具体取决于用户按下的选项。现在,应用程序只是在 asynctask 中调用 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 和应用程序不能同时调用 Web 服务器。由于现在已经实施,这是不可能的,因为它们是独立的。我正在考虑通过为所有这些调用创建意图,将应用程序中的所有 Web 调用传递给 IntentService。这行得通吗?如果有位置网络发送,来自应用调用的新意图将被放入队列并在当前调用之后立即执行?

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

谢谢。

后期编辑:

这是我所做的更改。

  1. 创建了自定义 Intent 服务
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();
      }
}

【问题讨论】:

    标签: android service intentservice android-intentservice android-webservice


    【解决方案1】:

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

    原代码为here

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

    所以你要做的就是:

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

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

    编码愉快。

    编辑:

    新编辑:

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

    stopSelf(msg.arg1);
    

    这会在所有消息被执行后停止服务,检查the docs

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

    请注意调用此函数的顺序。如果你打电话 此功能与您之前最近收到的 ID 为以前收到的 ID 调用它,该服务将立即 反正停了。如果您最终可能会乱序处理 ID(例如 通过在单独的线程上分派它们),那么您负责 按照您收到它们的相同顺序停止它们。

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

    【讨论】:

    • 谢谢@Budius,我不完全理解你的意思,但我会仔细调查你在那里所说的内容并尝试实施。
    • 我在每个对象的作用上添加了一些额外的 cmets 和额外的链接。它是 Android 线程模型的基础。在我看来,无论您尝试执行的当前代码如何,理解这些概念以便能够正确处理线程非常重要。 PS.:不要忘记检查执行者:developer.android.com/reference/java/util/concurrent/…
    • 请看看我到目前为止所做的事情并提出您的想法。谢谢,真的很感激。
    • 请查看我对答案所做的新编​​辑
    • 我真的不明白。 IntentService 不应该处理它在队列中接收到的所有意图吗?因此,如果我发送 5 个意图,则应该一个接一个地执行。据我所知,它只关注第一意图,其余的都被忽略了,这对我来说没有任何意义。
    猜你喜欢
    • 1970-01-01
    • 2013-06-04
    • 2018-11-28
    • 1970-01-01
    • 2011-12-20
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    • 2012-02-24
    相关资源
    最近更新 更多