我有一个活动正在运行,当然,在UI线程上,还有另一个线程在后台运行,并使用Handler post方法(通过looper)与活动进行通信。
当屏幕被打开或应用程序被隐藏时,它继续工作
所以我需要在onPause方法中停止这个线程并在onResume mehtod中唤醒它
在我的帖子中,我有条件暂停或停止
如何在onPause方法中让线程进入睡眠状态。并且在活动再次出现在前景之后将其唤醒
我可以使用监视器调用wait方法对一个对象执行此操作,然后通过此对象进行通知
但这是好方法吗?或者有另一种方式来优雅地做到这一点。
答案 0 :(得分:2)
听起来像是使用旋转门的好地方。用一个许可证初始化一个信号量:
Semaphore turnstile = new Semaphore(1);
定期进行背景活动通过旋转栅栏,如下所示:
turnstile.acquire();
turnstile.release();
当前台线程希望后台线程在旋转门处暂停时,它可以锁定旋转门:
turnstile.acquire();
当前台线程希望后台线程再次开始工作时,它可以解锁 turntile():
turnstile.release();
良好的软件工程实践是将整个事情包装在Turnstile
类中,并使用适当命名的方法来调用前台和后台线程。我将把它作为读者的练习。
答案 1 :(得分:1)
Android建议将服务用于长期后台任务,但如果您只是打开一个与Android生命周期相关的新线程,我不认为使用显示器和通话会很糟糕等待/通知。你能更具体地了解自己在做什么吗?
这是我如何停止和恢复已停止的线程的概述。 (您可能希望在您的实现中实现runnable)
class ThreadDemo extends Thread {
private Object monitor; //This is the monitor
private boolean keepRunning = true;
private Thread t;
ThreadDemo(){
System.out.println("Creating thread");
}
public void callinOnResume(){
synchronized(monitor){
monitor.notify();
}
}
public void callinOnPause(){
try {
synchronized(monitor){
System.out.println(threadName + "Waiting");
monitor.wait();
}
} catch (InterruptedException e) {
System.out.println("Thread interrupted " + e.toString());
}
}
public void run() {
System.out.println("Starting to loop.");
while (keepRunning) {
//stuff
}
System.out.println("Done looping.");
}
public void start ()
{
System.out.println("Starting " + threadName );
if (t == null)
{
t = new Thread (this, threadName);
t.start ();
}
}
}
答案 2 :(得分:0)
停止/恢复该线程之外的线程是一种不好的做法。线程必须决定何时运行以及何时停止。因此,后台线程应定期检查是否仍需要其工作,并且客户端(前台)线程应发出一些有关该信号的信号。
发出信号的一种方法是将信号形成为Runnable
类型的作业,然后在线程池上执行它们。因此,当活动休眠时,它不会发出信号。
后台线程想要更新UI时的主要问题是目标Activity
可以关闭(或者在重新创建过程中)并且更新任务失败。 AcyncTask
类无法解决此问题。正确的解决方案发布在my Github workspace。但在使用此解决方案或其他解决方案之前,如果您确实需要后台线程,请三思而后行。最好的方法是根本不使用后台线程,直接在UI线程上进行所有UI更新。当然,如果从网络获取更新,则必须使用后台线程。