自己动手写消息机制

客官°小女子只卖身不卖艺 2022-09-23 15:51 347阅读 0赞

首先,我们先别管Android中的消息机制,我们先来看一个需求:

在主线程中启动一个子线程去做一些事情,我希望子线程在做完这些事情后唤醒主线程来做一些相应的动作。

先想想怎么实现这个功能。直接在子线程回调一个接口?显然不行!

要让主线程感知到子线程的事情是否做完了。一般来说,就是在子线程完成事情后发送一些消息给主线程,让主线程知道子线程已经完成了工作,然后主线程去做相应的处理。这样一来,主线程就要变成一个死循环,无限循环的从消息队列中获取从子线程来的消息,并处理。

SouthEast

图中,主线程是一个轮询线程,主线程要做的事情就是,不断从消息队列中获取消息,并做处理。子线程处理完相关的业务之后,发送一个消息到消息队列中。整个过程是异步的。

同步:主线程启动一个子线程,在子线程执行过程中,主线程等待子线程完成后才继续往下运行

异步:主线程启动一个子线程,在子线程执行过程中,主线程也在运行

我们建立一个Java项目,简单模仿一下Android的消息机制

SouthEast 1

Looper是用来将线程变成一个轮询线程

  1. package com.zhanjixun;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. public class Looper {
  5. private static Map<Long, Looper> mLoopers = new HashMap<Long, Looper>();
  6. private MessageQueue mQueue = new MessageQueue();
  7. private Looper() {
  8. }
  9. public static void prepare() {
  10. long id = Thread.currentThread().getId();
  11. if (mLoopers.get(id) != null) {
  12. throw new RuntimeException("这线程的Looper已经调用prepare()");
  13. }
  14. mLoopers.put(id, new Looper());
  15. }
  16. public static void loop() {
  17. while (true) {
  18. Message next = myLooper().getMessageQueue().next();
  19. if (next != null) {
  20. if (next.getTarget() == null) {
  21. return;
  22. } else {
  23. next.getTarget().handlerMessage(next);
  24. }
  25. }
  26. }
  27. }
  28. public static Looper myLooper() {
  29. Looper looper = mLoopers.get(Thread.currentThread().getId());
  30. if (looper == null) {
  31. throw new RuntimeException(Thread.currentThread().getName()
  32. + "线程的Looper还没有调用prepare()");
  33. }
  34. return looper;
  35. }
  36. public MessageQueue getMessageQueue() {
  37. return mQueue;
  38. }
  39. }

其中的MessageQueue是用来管理Message的队列数据结构,先进先出原则

  1. package com.zhanjixun;
  2. import java.util.LinkedList;
  3. public class MessageQueue {
  4. private LinkedList<Message> mMsgs = new LinkedList<>();
  5. public void push(Message msg) {
  6. System.out.println("有消息进队列-->>>" + msg.toString());
  7. mMsgs.add(msg);
  8. }
  9. public Message next() {
  10. if (mMsgs.size() > 0) {
  11. Message removeFirst = mMsgs.removeFirst();
  12. System.out.println("有消息从队列被取出<<<---" + removeFirst.toString());
  13. return removeFirst;
  14. }
  15. return null;
  16. }
  17. }

Message类是对要发送的消息的一个封装

  1. package com.zhanjixun;
  2. public class Message {
  3. public int what;
  4. public Object obj;
  5. private Handler target;
  6. public Handler getTarget() {
  7. return target;
  8. }
  9. public void setTarget(Handler target) {
  10. this.target = target;
  11. }
  12. }

Handler负责发送Message以及轮询线程回调

  1. package com.zhanjixun;
  2. /**
  3. * Handler负责发送Message以及轮询线程回调
  4. *
  5. * @author doudian
  6. *
  7. */
  8. public class Handler {
  9. private Looper myLooper;
  10. /**
  11. * 创建Handler一定要在轮询线程中创建,因为创建的时候需要获取轮询线程的Looper
  12. */
  13. public Handler() {
  14. myLooper = Looper.myLooper();
  15. }
  16. public void sendMessage(Message message) {
  17. message.setTarget(this);
  18. myLooper.getMessageQueue().push(message);
  19. }
  20. public void handlerMessage(Message message) {
  21. }
  22. }

最后在Main方法中调用试试看成果

  1. package com.zhanjixun;
  2. public class Main {
  3. public static void main(String[] args) {
  4. Looper.prepare();
  5. Handler handler = new Handler() {
  6. @Override
  7. public void handlerMessage() {
  8. System.out.println(" doing something in "
  9. + Thread.currentThread().getName() + " thread");
  10. }
  11. };
  12. new Thread(new Runnable() {
  13. @Override
  14. public void run() {
  15. System.out.println(" doing something in "
  16. + Thread.currentThread().getName() + " thread");
  17. handler.sendMessage(new Message());
  18. }
  19. }).start();
  20. Looper.loop();
  21. throw new RuntimeException("主线程不小心停止了!");
  22. }
  23. }

运行结果

20160721131918242

源代码:http://download.csdn.net/detail/zhanjixun/9582075

写到这里大概就能明白整个消息机制的原理了:就是将主线程(也可以是其他子线程)变成一个死循环的线程,不断从队列中获取消息并处理;子线程处理一些业务,处理完毕就发送一个消息到消息队列中。

有空在分析一下Android中消息机制的源码

发表评论

表情:
评论列表 (有 0 条评论,347人围观)

还没有评论,来说两句吧...

相关阅读

    相关 自己动手ajax框架

    闲来无事就开始琢磨怎么提高网站效率。。。。。然后就对jquery的框架很感兴趣。。 本来很可惜jq没有一个定制的功能,把需要的功能提出来之后不是可以减少很多体积么。 没办法

    相关 自己动手爬虫》笔记

    《自己动手写爬虫》这本书总体介绍了整个网络爬虫由浅入深的知识体系,将爬虫中每个部分分割开来具体的细讲,非常适合新手来入门,由于之前只知道使用爬虫框架,所以一遇到一些错误或者想调