如何按条件唤醒线程

How to wake thread by condition

我有一个 activity 运行,当然,在 UI 线程上,还有另一个线程 运行 在后台并与 activity 通信使用处理程序 post 方法(通过循环程序)。
当屏幕关闭或应用程序隐藏时,它会继续工作。
所以我需要在 onPause 方法中停止这个线程并在 onResume 方法中唤醒它。
在我的线程中,我有条件暂停或停止它。
如何让线程在 onPause 方法中休眠。并在 activity 再次出现在前台后将其唤醒。
我可以使用监视器调用 wait 方法对一个对象执行此操作,而不是通知该对象。
但这是好方法吗?或者还有另一种方法可以优雅地做到这一点。

Android 建议将服务用于长期后台任务,但如果您只是打开一个与 Android 生命周期相关的新线程,我认为这不会很糟糕使用监视器并调用 wait/notify。你能更具体地说明你在做什么吗?

这是我将如何停止和恢复已停止线程的概述。 (你可能想在你的中实现 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 ();
      }
   }
 }

听起来是使用 旋转门 的好地方。使用一个许可初始化信号量:

Semaphore turnstile = new Semaphore(1);

让你的背景activity定期通过旋转门,像这样:

turnstile.acquire();
turnstile.release();

当前台线程想让后台线程在转门处暂停时,可以锁定转门:

turnstile.acquire();

并且当前台线程希望后台线程再次开始工作时,它可以解锁 turnstile():

turnstile.release();

好的软件工程实践是将整个事情包装在 Turnstile class 中,并使用适当命名的方法供前台和后台线程调用。我将把它留作 reader.

的练习

在该线程之外 stop/resume 线程是一种不好的做法。线程必须自行决定何时 运行 以及何时停止。因此,后台线程应定期检查是否仍需要其工作,并且客户端(前台)线程应发出一些相关信号。 发出信号的一种方法是将该信号形成为 Runnable 类型的作业,然后在线程池上执行它们。所以当 activity 休眠时,它只是不发出信号。

当后台线程想要更​​新UI时的主要问题是目标Activity可以关闭(或在重建过程中)并且更新任务失败。 AcyncTask class 没有解决这个问题。 my Github workspace 上发布了正确的解决方案。但在使用这个或另一个解决方案之前,如果您真的需要后台线程,请三思。最好的方法是根本不使用后台线程,直接在 UI 线程上进行所有 UI 更新。当然,如果更新是从网络上获取的,那么就必须使用后台线程。