在后台线程中运行处理程序消息
Posted
技术标签:
【中文标题】在后台线程中运行处理程序消息【英文标题】: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。 【参考方案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
是什么意思。
听起来您需要一个线程,该线程由队列执行。您可能会从调查Executor
s 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...
【讨论】:
以上是关于在后台线程中运行处理程序消息的主要内容,如果未能解决你的问题,请参考以下文章