当前位置: 首页 > 知识库问答 >
问题:

在IntentService中优先考虑意图

陈斌
2023-03-14

我现在是这样做的:

>

  • 我有一个在后台运行并读取用户位置的服务。每次读取一个有效的位置(有一些参数,如距离和时间),一个IntentService开始将该位置发送到网络服务器

    使用追踪服务的应用程序也有一些网络通话,具体取决于用户按下的选项。现在,应用程序只是在异步任务中调用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
    }
    

    以下是我需要做出的改变:

    >

  • IntentService和应用程序不能同时调用web服务器。由于现在已经实施,这是不可能的,因为它们是独立行动的。我在考虑通过为所有应用程序创建意图,将所有web调用从应用程序传递到IntentService。这样行吗?如果有一个位置在网上发送,来自应用程序调用的新意图将被放入队列,并在当前调用后立即执行?

    如果由于网络速度较低,队列中有多个位置发送,则应用程序调用需要放在队列前面,而不是等待所有现有意图完成,只等待当前意图完成。有没有办法把意图放在最前面?

    非常感谢。

    稍后编辑:

    以下是我所做的改变。

    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);
      }
    }
    
    public class LocationManagerIntentService extends PriorityIntentService {
    
        @Override
          protected void onHandleIntent(Intent intent) {
    
          intentFinished();
          }
    }
    
  • 共有1个答案

    颛孙英勋
    2023-03-14

    您想要做的是不可能的,因为IntentService是构建的方式,但是,IntentService是一个非常简单的代码,并且是开源的,所以您可以通过一些修改来创建自己的版本。

    原始代码在这里。

    onCreate()方法中,您可以看到Service在哪里创建HandlerThreadHandlerThread来调度所有onhandleContent调用。

    所以你要做的就是:

    >

  • 为整个应用程序创建一个单独的HandlerThreadHandler。每个网络调用或CustomIntentService都应该调用这个处理程序。这是第一部分。你只是强迫所有的网络通话不能同时发生。

    现在,所有的调用都通过同一个线程和处理程序,只需调用处理程序即可。PostAfrontofQueue对某些执行进行优先级排序。

    快乐编码。

    编辑:

    >

  • HandlerThread:未完成的线程。它有一个“活套”,使线程保持活力。https://developer.android.com/reference/android/os/HandlerThread.html

    Handler:一个包含循环器的线程的句柄。通过这个句柄,任何线程都可以向这个句柄线程发送消息runnable。消息将在句柄handleMessage(Message)回调中执行,并且Runnables将具有run()方法executed.https://developer.android.com/reference/android/os/Handler.html

    所有这些Handler的东西都被漏斗到MessageQueue中,这对于每个循环/线程都是唯一的。https://developer.android.com/reference/android/os/MessageQueue.html

    新编辑:

    它不执行的原因如下:

    stopSelf(msg.arg1);
    

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

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

    对这个函数调用的顺序要小心。如果在调用此函数之前,先使用最近收到的ID调用此函数,然后再调用以前收到的ID,则服务将立即停止。如果最终处理ID的顺序不正确(比如在不同的线程上分派ID),那么您有责任按照收到ID的顺序停止它们。

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

  •  类似资料:
    • 我正在使用for。对于这个我正在使用,https://github.com/vyuldashev/laravel-queue-rabbitmq. 对于正常队列和消费者,一切都很好。为了区分消息的优先级,我定义了多个队列,在队列名中使用0-3作为后缀。我通过手动计算作业总数,将作业路由到不同的队列。 使用这种方法,对于不同的任务,我需要创建更多具有名称优先级的队列。创建队列名称中包含 0-3 的队列

    • 条款 13:优先考虑const_iterator而非iterator STL const_iterator等价于指向常量的指针。它们都指向不能被修改的值。标准实践是能加上const就加上,这也指示我们对待const_iterator应该如出一辙。 上面的说法对C++11和C++98都是正确的,但是在C++98中,标准库对const_iterator的支持不是很完整。首先不容易创建它们,其次就算你有

    • 条款八:优先考虑nullptr而非0和NULL 你看这样对不对:字面值0是一个int不是指针。 如果C++发现在当前上下文只能使用指针,它会很不情愿的把0解释为指针,但是那是最后的退路。 一般来说C++的解析策略是把0看做int而不是指针。 实际上,NULL也是这样的。但在NULL的实现细节有些不确定因素, 因为实现被允许给NULL一个除了int之外的整型类型(比如long)。 这不常见,但也算不

    • 条款九:优先考虑别名声明而非typedefs 我相信每个人都同意使用STL容器是个好主意,并且我希望Item18能说服你让你觉得使用std:unique_ptr也是个好主意,但我猜没有人喜欢写上几次 std::unique_ptr<std::unordered_map<std::string,std::string>>这样的类型,它可能会让你患上腕管综合征的风险大大增加。 避免上述医疗悲剧也很简单

    • 我有一个Spring Boot应用程序,它充当Eureka客户机。该应用程序需要通过REST调用另一个微服务,我希望使用Feign进行此调用。我遇到的问题是,我的应用程序试图在Eureka中查找服务名称,而它仅在我的应用程序yaml文件中定义。 我为难以理解的解释道歉,希望下面的代码片段将有助于澄清。 外国客户: 在我的控制器中,谁调用这个费恩客户端,使用@AutoWired定义了foServic

    • 让我们先对std::make_unique和std::make_shared做个铺垫。std::make_shared是C++11标准的一部分,但很可惜的是,std::make_unique不是。它从C++14开始加入标准库。如果你在使用C++11,不用担心,一个基础版本的std::make_unique是很容易自己写出的,如下: template<typename T, typename...