【问题标题】:Run Handler messages in a background thread在后台线程中运行处理程序消息
【发布时间】:2013-09-12 17:39:01
【问题描述】:

我想在后台线程中运行一些 Runnable。我想使用 Handler 因为它方便延迟。 我的意思是

handler.post(runnable, delay);

runnable 应该在 background 线程中运行。 是否可以创建这样的处理程序? 某处是否有“背景” Looper,或者我该如何创建它?

附:我知道如何使用自定义类扩展 Thread 来做到这一点,但它需要比处理程序方式更多的编码工作。所以请不要发布其他解决方案或类似的东西

handler.post(new Runnable() {
    @Override
    public void run() {
        new Thread() {
            @Override
            public void run() {
                //action
            }
        }.start();
    }
});

如果 Handler 能以“干净”的方式做到这一点,我只是徘徊。

【问题讨论】:

  • 你不能从后台线程运行其他线程。您只能从主线程执行此操作。所以如果你想运行线程,你可以使用:getActivity().runOnUiThread(new Runnable() { ....在这里你创建新的处理程序。
  • @daro2189 我想从主线程运行一个后台线程,但是延迟了。我看到 Handler 可以从任何拥有它的线程中接受 Looper。我只是不知道是否可以在后台线程中创建 Looper。

标签: java android multithreading handler


【解决方案1】:

你可以这样做:

private Handler mHandler;

private HandlerThread mHandlerThread;

public void startHandlerThread(){
    mHandlerThread = new HandlerThread("HandlerThread");
    mHandlerThread.start();
    mHandler = new Handler(mHandlerThread.getLooper());
}

然后调用:

mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
          // Your task goes here
        }
    },1000);

【讨论】:

  • 添加正确的顺序来停止所有事情会很有帮助。
  • 如果我想在run里面更新UI我需要调用runonuithread吗?
  • 为了避免内存泄漏可以使用WeakHandler代替Handler;
【解决方案2】:

你可以试试这样的

    private void createHandler() {
        Thread thread = new Thread() {
            public void run() {
                Looper.prepare();

                final Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                       // Do Work
                        handler.removeCallbacks(this);
                        Looper.myLooper().quit();
                   }
                }, 2000);

                Looper.loop();
            }
        };
        thread.start();
    }

【讨论】:

  • 这个想法类似于我在荒木雄一为我指出正确方向后所做的。当然,应该将 Handler 分配给一个字段。
  • 是的,只是一个完整的例子。
  • 我们是否也应该在一切完成后对线程本身进行清理?
  • 这个对我有用。谢谢@AymanMahgoub
【解决方案3】:

您可以使用 Looper.prepare()Looper.loop 在后台线程中设置 Looper。

【讨论】:

  • 这似乎是我想要的。我正在查看通过方法运行的同一个文档,但不知何故我错过了文档 xD 标题中的示例。
  • 关于[Loopers and Handlers]的好文章mindtherobot.com/blog/159/…
【解决方案4】:

不清楚Handler是什么意思。

听起来您需要一个线程,该线程由队列执行。您可能会从调查Executors here 中受益,但这里有一个通过队列进行通信的简单双线程对。

public class TwoThreads {
  public static void main(String args[]) throws InterruptedException {
    System.out.println("TwoThreads:Test");
    new TwoThreads().test();
  }
  // The end of the list.
  private static final Integer End = -1;

  static class Producer implements Runnable {
    final Queue<Integer> queue;

    public Producer(Queue<Integer> queue) {
      this.queue = queue;
    }

    @Override
    public void run() {
      try {
        for (int i = 0; i < 1000; i++) {
          queue.add(i);
          Thread.sleep(1);
        }
        // Finish the queue.
        queue.add(End);
      } catch (InterruptedException ex) {
        // Just exit.
      }
    }
  }

  static class Consumer implements Runnable {
    final Queue<Integer> queue;

    public Consumer(Queue<Integer> queue) {
      this.queue = queue;
    }

    @Override
    public void run() {
      boolean ended = false;
      while (!ended) {
        Integer i = queue.poll();
        if (i != null) {
          ended = i == End;
          System.out.println(i);
        }
      }
    }
  }

  public void test() throws InterruptedException {
    Queue<Integer> queue = new LinkedBlockingQueue<>();
    Thread pt = new Thread(new Producer(queue));
    Thread ct = new Thread(new Consumer(queue));
    // Start it all going.
    pt.start();
    ct.start();
    // Wait for it to finish.
    pt.join();
    ct.join();
  }
}

【讨论】:

  • 感谢您的回答。执行器不适合,因为只有一个线程必须延迟启动,但如果在延迟用完之前发生某些情况,则取消。 Handler 非常适合这个,但我想在后台运行 Runnable,而不是在默认情况下运行 Handler 的主线程中。
【解决方案5】:

我在 kotlin 中实现了在后台线程上运行任务的简单方法:

fun background(function: () -> Unit) = handler.post(function)

private val handler: Handler by lazy { Handler(handlerThread.looper) }

private val handlerThread: HandlerThread by lazy {
    HandlerThread("RenetikBackgroundThread").apply {
        setUncaughtExceptionHandler { _, e -> later { throw RuntimeException(e) } }
        start()
    }
}

一般的想法是,任务很容易执行,并且一个接一个地依次运行,未捕获的异常被传播到主线程,这样它们就不会丢失。后面的函数基本上是在主线程上运行的处理程序。

所以你可以像这样简单地发布任务:

 background {
    some task to do in background...  
 }

一些小事

 background {
    other task to do in background...  
    later {
        on main thread when all tasks are finished...
    }
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-05
    • 2020-04-22
    • 2021-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多