处理程序,MessageQueue,Looper,他们都运行在UI线程?
我试图围绕线程化头,而且我知道我可以使用Handler
将消息/ runnables发布到MessageQueue
,然后由Looper
并发送回Handler进行处理。
如果我发布到我的活动中的处理程序, Activity
, Handler
, MessageQueue
和Looper
都在UI线程上运行? 如果没有,请问有人能解释一下这一切吗? 🙂
简短的回答:他们都在同一个线程上运行。 如果从Activity
生命周期callback中实例化,它们都在主UI线程上运行。
很长的回答:
一个线程可能有一个Looper
,它包含一个MessageQueue
。 为了使用这个工具,你必须通过调用(静态的) Looper.prepare()
在当前线程上创build一个Looper
,然后通过调用(也是静态的) Looper.loop()
启动循环。 这些是静态的,因为每个线程只能有一个Looper
。
对loop()
的调用通常不会返回一段时间,而是继续从MessageQueue
取出消息(“任务”,“命令”或任何你喜欢调用它们的东西)并单独处理它们(例如,通过调用一个包含Runnable
在消息中)。 当队列中没有消息时,线程会阻塞,直到有新消息。 要停止一个Looper
,你必须在它上面调用quit()
(它可能不会立即停止循环,而是设置一个循环定期检查的私有标志,通知它停止)。
但是,您无法直接将消息添加到队列中。 相反,你注册一个 MessageQueue.IdleHandler
来等待一个queueIdle()
callback,在这个callback中你可以决定你是否想要某个东西。所有的处理程序依次被调用。 (所以“队列”不是一个真正的队列,而是定期调用的一组callback 。)
关于前一段的注意事项:这个我其实已经猜到了。 我找不到任何文件,但它是有道理的。
更新:查看ahcox的评论和他的答案 。
因为这是很多工作,框架提供了Handler
类来简化事情 。 当你创build一个Handler
实例时,(默认情况下)绑定到已经附加到当前线程的Looper
。 ( Handler
知道什么Looper
附加到,因为我们早些时候调用了prepare()
,它可能在ThreadLocal
存储了对Looper
的引用。)
使用Handler
,你可以调用post()
来“把消息放入线程的消息队列”(可以这么说)。 Handler
将负责所有的IdleHandler
callback的东西,并确保您的发布Runnable
执行。 (如果你延迟发布,它也可能检查时间是否已经正确。)
只是要清楚:实际上做一个循环线程的唯一方法是做一些事情是发送一个消息到它的循环。 这个有效直到你在循环中调用quit()。
关于android UI线程:在某个时候(可能在创build任何活动之前),框架已经build立了一个Looper
(包含一个MessageQueue
)并启动它。 从这个angular度来看,在UI线程上发生的所有事情都是通过这个循环。 这包括活动生命周期pipe理等等。 你重写的所有callbackonCreate()
( onCreate()
, onDestroy()
…)至less是从这个循环中间接调用的。 你可以看到,例如在一个exception的堆栈跟踪。 (你可以试试,只要写int a = 1 / 0;
onCreate()
int a = 1 / 0;
在onCreate()
…)
我希望这是有道理的。 对不起,以前不清楚。
跟进“这是怎么一回事”的部分问题。 如user634618写的,循环者接pipe一个线程,在应用程序的主Looper
情况下是主UI线程。
-
Looper.loop()
将消息从其消息队列中拉出。 每条消息都有一个对关联的Handler的引用,它将被返回给(目标成员)。 - 从队列中获取每个消息的
Looper.loop()
内部:- 使用存储在消息中的Handler作为其目标成员,
loop()
调用public void Handler.dispatchMessage(Message msg)
。 - 如果消息具有Runnablecallback成员,则运行该成员。
- 否则,如果处理程序具有共享的callback集,则运行。
- 否则,Handler的
handleMessage()
被作为参数调用。 (请注意,如果您将AsyncTask作为子类Handler,那么您可以重写handleMessage()
。)
- 使用存储在消息中的Handler作为其目标成员,
在关于所有协作对象位于同一UI线程上的问题上,必须在与发送消息的Looper
相同的线程上创buildHandler
。 它的构造函数将查找当前的Looper
并将其存储为一个成员,将Handler
绑定到该Looper
。 它还会直接在自己的成员中引用Looper
的消息队列。 Handler
可以用来从任何线程向Looper
发送工作,但是这个消息队列的标识将路由在Looper
线程上完成的工作。
当我们在另一个线程上运行一些代码,并想发送一个Runnable在UI线程上执行时,我们可以这样做:
// h is a Handler that we constructed on the UI thread. public void run_on_ui_thread(final Handler h, final Runnable r) { // Associate a Message with our Handler and set the Message's // callback member to our Runnable: final Message message = Message.obtain(h, r); // The target is the Handler, so this asks our Handler to put // the Message in its message queue, which is the exact same // message queue associated with the Looper on the thread on // which the Handler was created: message.sendToTarget(); }
我试图自己实现这些接口来理解这个概念。 通过简单,只需要使用接口。 这是我的testing代码:
import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class TestLooper { public static void main(String[] args) { UIThread thread = new UIThread(); thread.start(); Handler mHandler = new Handler(thread.looper); new WorkThread(mHandler, "out thread").run(); } } class Looper { private BlockingQueue<Message> message_list = new LinkedBlockingQueue<Message>(); public void loop() { try { while (!Thread.interrupted()) { Message m = message_list.take(); m.exeute(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void insertMessage(Message msg) { message_list.add(msg); } } class Message { String data; Handler handler; public Message(Handler handler) { this.handler = handler; } public void setData(String data) { this.data = data; } public void exeute() { handler.handleMessage(this); } } class Handler { Looper looper; public Handler(Looper looper) { this.looper = looper; } public void dispatchMessage(Message msg) { System.out.println("Handler dispatchMessage" + Thread.currentThread()); looper.insertMessage(msg); } public Message obtainMessage() { return new Message(this); } public void handleMessage(Message m) { System.out.println("handleMessage:" + m.data + Thread.currentThread()); } } class WorkThread extends Thread { Handler handler; String tag; public WorkThread(Handler handler, String tag) { this.handler = handler; this.tag = tag; } public void run() { System.out.println("WorkThread run" + Thread.currentThread()); Message m = handler.obtainMessage(); m.setData("message " + tag); handler.dispatchMessage(m); } } class UIThread extends Thread { public Looper looper = new Looper(); public void run() { //create handler in ui thread Handler mHandler = new Handler(looper); new WorkThread(mHandler, "inter thread").run(); System.out.println("thead run" + Thread.currentThread()); looper.loop(); } }
如果我发布到我的活动中的处理程序,Activity,Handler,MessageQueue和Looper是否都在UI线程上运行? 如果没有,请问有人能解释一下这一切吗? 🙂
这取决于你如何创buildHandler
情况1:
Handler()
默认构造函数将这个处理程序与当前线程的Looper关联起来。
如果在UI线程中像这样创buildHandler
,则Handler
与UI Thread的Looper
关联。 MessageQueue
也与UI线程的Looper
相关联。
案例2:
Handler (Looper looper)
使用提供的Looper而不是默认的。
如果我创build一个HandlerThread并将HandlerThread的Looper传递给Handler,则Handler和Looper与HandlerThread关联而不是UI Thread。 Handler
, MessageQueue
和Looper
与HandlerThread
相关联。
使用案例:您想要执行networking或IO操作。 你不能在UI线程上执行它,因此HandlerThread
对你来说很方便。
HandlerThread handlerThread = new HandlerThread("NetworkOperation"); handlerThread.start(); Handler requestHandler = new Handler(handlerThread.getLooper());
如果你想从HandlerThread传递数据到UI线程,你可以使用UI Thread中的Looper
创build一个更多的Handler(比如responseHandler),并调用sendMessage
。 UI线程responseHandler
应该重写handleMessage
请参阅这些post了解更多详情。
Looper的目的是什么?如何使用它? (对于概念)
Android:在一个线程中吐出 (例如,通过链接所有这些概念的代码)