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

IntentService不开火

邬宏扬
2023-03-14

我的应用程序通过web服务调用与远程数据库同步数据。我在IntentService中进行这些调用,以便它们可以在后台运行(我称之为SyncService)。

启动my IntentService的代码如下所示:

Intent intent = new Intent();
intent.setClass(appContext, SyncService.class);

// place additional values in intent
intent.putExtra("data_type", SyncService.ITEM_TRACKING);
intent.putExtra("user_id", intUserId);

// call SyncService
appContext.startService(intent);

通常情况下,这个看起来很棒。然而,我的一个朋友,也是我的应用程序的用户,经常告诉我他的数据不同步并显示在我们的网站上。我在的时候,他的设备碰巧出现了症状。我把他的设备插入我的电脑,我发现:

  • 启动SyncService的代码(即:上面的代码)被命中
  • 我的IntentService的onHandleIntent方法中有一个断点,它从未被击中
  • 我查看了他的设备上运行的服务列表,SyncService在那里并在运行。有趣的是,它已经运行了大约20分钟。我的印象是,IntentService在完全无意处理时自杀了
  • 我强制停止了SyncService(而不是应用程序),突然,OnHandleContent开始一次又一次地受到攻击。就好像所有的意图都在设备上的某个地方排队,而现在却被扔到了同步服务上

有人知道问题出在哪里吗?你认为这是我的应用程序的问题吗?用Android?

我再次向Android发送了一条消息:“启动此IntentService或将消息发送到已经运行的IntentService。”在那一点上,我无法控制。这条消息永远不会传到IntentService。一旦我强制退出应用程序,消息就会被发送到IntentService,它就会完成它的工作。

更新:我认为这段代码很好,但我会把它贴出来,因为你们很多人可能都想看。

进入IntentService的每一个意图都有一个额外的指示,指示对我进行的调用的“类型”(即:我是调用这个web服务还是那个web服务,等等)。当意向进入IntentService时,我会检查“类型”,如果队列中已经有该类型的意向,我会在其中添加一个名为“跳过”的额外内容,以便在到达时,我不执行搜索(基本上IntentService可以建立很多意图,当20秒前调用此web服务时调用此web服务是没有意义的)。它基本上可以保护应用程序免受对html" target="_blank">网站的垃圾邮件攻击。

重要的是要注意,这些代码无论如何都不会被命中(一旦问题开始发生)。在应用程序被终止之前,不会调用onStartCommand

    @Override
    public int onStartCommand (Intent intent, int flags, int startId) {
        // here be dragons
        // overriding this method and adding your own code is dangerous. i've wrapped
        // my code in a try/catch because it is essential that the super method be called
        // every time this method is entered. any errors in my code should not prevent this
        // or the app will explode.
        try {
            if (flags == 0 && intent != null && intent.hasExtra("data_type")) {
                Integer intDataType = intent.getExtras().getInt("data_type");

                    if (!mCurrentTypes.containsKey(intDataType)
                            || !mCurrentTypes.get(intDataType)) {
                        mCurrentTypes.put(intDataType, true);  // put this type in the list and move on
                    }
                    else {
                        intent.putExtra("skip", true);  // mark this Intent to be skipped
                    }
            }
        }
        catch (Exception e) {
            // Log.e("Error onStartCommand", "error: " + e);
        }

        return super.onStartCommand(intent, flags, startId);
    }


private void processIntent(Intent intent) {
        // do stuff if no "skip" Extra
        mCurrentTypes.put(intDataType, false);
    }

共有3个答案

令狐泓
2023-03-14

在我看来,根据你的意图设置一组标志可能会解决这个问题。

Intent intent = new Intent();
intent.setClass(appContext, SyncService.class);
// This way    
intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK|Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);

您可以在一个新任务中使用上面的标志使您的服务以新的方式启动。

齐凯康
2023-03-14

这个答案提出了一个在类似情况下对我有效的解决方案。它不会修复您当前的代码,但建议了另一个可能更简单(更容易调试)的选项:

>

  • 将一个广播接收器添加到您的呼叫活动,该活动监听来自IntentService的成功意图

    在调用活动时,包含何时启动IntentService的逻辑(不要包含在IntentService中)。逻辑是:

    • 调用startService(),并在调用活动中设置一个标志,使其无法调用

    在您的IntentService中,像这样编写onStartCommand()

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }
    

    在您的IntentService中,当您接收、解析并存储web服务响应时,调用sendBroadcast(),以获得自定义操作成功。

    这个逻辑只是一个大纲,必须对来自Web服务的错误消息进行微调,这些错误消息必须从IntentService广播到监听活动

    希望这有帮助。

  • 武彭薄
    2023-03-14

    肯定有什么东西可以让你的服务在朋友的设备上运行。如果是这样,则对该意向服务的所有后续调用都将排队,直到当前调用完成。如果它没有完成,那么你将得到你所拥有的:下一个服务将不会启动。

    你应该仔细检查一下:

    • 你给了网络操作适当的暂停时间
    • 您为网络连接操作提供了适当的暂停时间
    • 线程之间没有竞争条件
    • 如果您记录了服务内部可能发生的任何异常,您不希望丢失此类信息

    之后,如果你认为一切都是绿色的:只需记录该服务的功能,并使用一些错误报告机制,让它自动从你的朋友设备发送。一个简单的解决方案可以是使用bugsense或等效工具。

    接下来,设置某种看门狗:一个线程将继续运行,直到服务停止(当服务停止时,您只需告诉线程停止)。线程将不得不在超过某个时间限制后停止您的服务。

    这个看门狗线程可以放在服务本身内部,也可以放在服务外部,尽管这可能更复杂。

     类似资料:
    • 13.4.IntentService 我们已对系统服务的工作方式有所了解,接下来可以利用系统服务的有关特性,简化UpdaterService的实现。回忆下前面的内容:UpdaterService会一直运行,定期从服务端抓取Timeline的更新。由于Service默认与UI在同一个线程(或者说,都在UI线程中执行)中执行,为避免网络操作造成界面的响应不灵,我们需要新建一个Updater线程,并将U

    • 一、 定义 IntentService是Android里面的一个封装类,继承自四大组件之一的Service。 二、作用 处理异步请求,实现多线程。 三、 工作流程 注意:若启动IntentService多次,那么每个耗时操作则以队列的方式在IntentService的onHandleIntent回调方法中依次执行,执行完自动结束。 四、实现步骤 步骤1:定义IntentService的子类:传入线

    • 由于Android Oreo后台执行限制,文档建议将重构为。 立即作为Oreo下面的运行,但在Oreo+上调度作业 https://developer.android.com/reference/android/support/v4/app/jobintentservice 在什么情况下,将正常的作为前台运行并带有持久通知是有意义的,何时更好? 我可以在中看到一个缺点是它不能立即启动。

    • 我试图发送一个意图,从一个活动中的创建启动一个意图服务。但是,IntentService的onHandleIntent永远不会被接收。我尝试过用意图过滤器改变清单,但似乎没有任何效果。没有抛出异常,但是根本没有调用IntentService。 这是onCreate 这是IntentService类的创建者和OnHandleContent,我知道它不会被调用,因为logcat从不显示“检索到的意图”

    • 我正在尝试为muzei创建一个艺术源(插件)。 该应用程序应该提供一个新的艺术源,在我的情况下,它是我的应用程序私人空间的文件夹。 按照muzei api中的示例及其提供的详细信息,我为我的应用程序创建了一个文件提供程序。 我已将此代码添加到我的清单: 我在我的res/xml文件夹中创建了xml文件: 如您所见,它指向我的文件夹。 最后一个是我的类,它扩展了: 在我看来,这是返回简单文件(名为wa

    • 我有一个稍微令人困惑的问题,我认为由于一个愚蠢的疏忽,这将是一个容易解决的问题。 我的主要任务是上传图像和录音文件到我的服务器上的一个位置。我通过FTP这样做。 活动通过startService(intentName)调用服务 onHandleIntent()创建一个新线程 在新线程中,需要上传的文件被放入一个列表数组 在列表数组中循环。在这个循环中,将文件名传递给FTP服务器。如果添加成功,我会