handler.postDelayed在IntentService的onHandleIntent方法中无法工作

10
final Handler handler = new Handler();
LOG.d("delay");
handler.postDelayed(new Runnable() {
    @Override public void run() {
        LOG.d("notify!");
        //calling some methods here
    }
}, 2000);

"delay" 在日志中确实显示了,但其他代码完全没有执行。而且在 run() 方法中调用的方法也完全没有被执行。请问有谁能帮忙解释一下为什么会出现这种情况吗?我做错了什么吗?

拥有该代码的类扩展了 IntentService,这会有问题吗?

============================

更新: 我把这段代码放在扩展了 IntentService 的类中。我发现它只能在构造函数中运行。但我需要将其放在 onHandleIntent 方法中。所以我查看了 onHandleIntent 的文档, 文档中说:

此方法在工作线程上被调用以处理请求。每次只处理一个 Intent,但处理过程在独立于其他应用程序逻辑的工作线程上运行。因此,如果此代码需要很长时间,它将阻止对同一 IntentService 的其他请求,但不会阻止任何其他事情。当处理完所有请求后,IntentService 会停止自身,因此您不应调用 stopSelf。

基于我得到的结果,我觉得我不能在“工作线程”中使用 postDelayed。但是有人可以更详细地解释一下吗,比如为什么它在工作线程中不能工作?提前感谢您的回答。


2
os.Handler 是从哪里导入的? - N J
1
为什么@Override在public旁边而不是上面?为什么是“LOG.d”而不是“Log.d(“your tag”,“ notify!”)”? 如果您确实导入了os.Handler,那么它应该可以工作。 - UFC Insider
1
IntentService通常用于不需要与主线程通信的长时间任务。也许可以解释一下你想要实现什么。 - UFC Insider
你是怎么解决这个问题的?我遇到了类似的情况...只不过我在IntentService中使用了handler.sendEmptyMessageDelayed,我的下一步尝试会和你卡住的地方一样...我的屏幕也是亮着的,所以应该不是wakelock的问题... - AA_PV
经过尝试和确认,使用普通服务而不是IntentService解决了这个问题。 - AA_PV
显示剩余6条评论
7个回答

17

转换

final Handler handler = new Handler();

final Handler handler = new Handler(Looper.getMainLooper());

这对我起了作用。


只要您在主线程中实例化处理程序,这就没有任何影响。 - CopsOnRoad
@CopsOnRoad 这会有所不同,IntentService的onHandleIntent在它自己的线程中运行。 - Pierre

12

您正在使用主线程的循环器。 您必须创建一个新的循环器,然后将其传递给您的处理程序。

HandlerThread handlerThread = new HandlerThread("background-thread");
handlerThread.start();
final Handler handler = new Handler(handlerThread.getLooper());
handler.postDelayed(new Runnable() {
    @Override public void run() {
        LOG.d("notify!");
        // call some methods here

        // make sure to finish the thread to avoid leaking memory
        handlerThread.quitSafely();
    }
}, 2000);

或者您可以使用Thread.sleep(long millis)。

try {
    Thread.sleep(2000);
    // call some methods here

} catch (InterruptedException e) {
    e.printStackTrace();
}

如果您想停止一个正在睡眠的线程,请使用yourThread.interrupt();


1

这是我使用处理程序的方式:

import android.os.Handler;

Handler handler;
//initialize handler
handler = new Handler();

//to start handler
handler.post(runnableName);

private Runnable runnableName= new Runnable() {
        @Override
        public void run() {
            //call function, do something
            handler.postDelayed(runnableName, delay);//this is the line that makes a runnable repeat itself
        }
};

谢谢回答,但它不起作用。我不知道是因为我不能将这个家伙放在某些线程中还是其他原因。 - Zip
但是我无法在我的项目中导入android.os.Handler。 - Prince Dholakiya
在调用handler.post之前,runnableName不应该被赋值吗? - kbsbng
@kbsbng 不,把它看作一个方法就行。 - rmanalo
@Zip 我认为你不应该将ThreadHandler结合在一起使用。它们有点类似,所以你只需要选择其中一个来使用。 - rmanalo
@DPrince,如果你在代码顶部放了导入语句,请尝试将其删除。有时候,如果你打开了自动导入功能,Android Studio会自动导入正确的语句。如果不行,Handler一词应该是红色的。把光标放在上面,它会出现下划线,然后按Alt+Enter。导入选项会出现,选择os.Handler即可。 - rmanalo

0

当设备屏幕开启时,处理程序和服务将变得可预测。例如,如果设备进入睡眠状态,则处理程序将不是可行的解决方案。

一个更好、更可靠的解决方案是使用以下代码:

AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

不要试图延迟几秒钟。 - Saik Caskey
你有这个声明的参考资料吗?我问这个问题是因为我的处理程序在屏幕关闭约15分钟后会变得不可预测。 - galaxigirl

0

IntentService 不适用于这种情况。您可以使用常规的 Service。您可以将处理程序放在 onStartCommand() 中。不要忘记在 handler.postDelayed(){} 后调用 stopSelf() 来关闭服务实例。


0
最简单的方法是在onHandleIntent()结束之前等待:
SystemClock.sleep(2000);

0

我的回答并不能解决你的特定问题。

我将这个回答提供给那些需要安排多个任务并在它们之间设置小延迟,但从handler.postDelayed中得到意外行为的人。

我尝试实现具有固定延迟的任务。我尝试使用for循环编写了下面的代码,但它只是将所有任务都安排在sum(delays)的时间点运行。后来我通过使用递归来修复了这个问题。

for循环代码(不起作用

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)
        val handler = Handler(Looper.getMainLooper())
        // code to fetch instructions from intent
        var cummulativeDelay = 0L
        for (instruction in instructions) {
            val handler = Handler(Looper.getMainLooper())
            handler.postDelayed({
                executeInstruction(instruction)
            }, cummulativeDelay)
            cummulativeDelay += instruction.delay
        }
    }

递归代码(这个有效)
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)
        val handler = Handler(Looper.getMainLooper())
        // code to fetch instructions from intent
        executeInstructions(instructions, 0, handler)
    }

    private fun executeInstruction(instruction: Instruction) {
        // execute the instruction
    }

    private fun executeInstructions(instructions: List<Instruction>, i: Int, handler: Handler) {
        if (i == instructions.size) {
            stopSelf()
            return
        }
        val instruction = instructions[i]
        try {
            executeInstruction(instruction)
        } catch(e: Exception) {
            e.printStackTrace()
        }
        val delay = /* delay in milliseconds */
        handler.postDelayed({
            executeInstructions(instructions, i+1, handler)
        }, delay)
    }

是因为批处理延迟指令的小延迟吗?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接