美文网首页
Android Handler消息传递机制

Android Handler消息传递机制

作者: lxbnjupt | 来源:发表于2018-07-10 16:22 被阅读0次

    一、Handler消息传递机制简介

    1.什么是Handler

    Handler是Android的一套消息传递机制。在Android开发的多线程应用场景中,Handler机制十分常用。

    2.Handler有什么作用

    Handler的作用就是实现消息的异步处理。例如,在多线程应用场景中,将工作线程中需更新UI的操作信息传递到主线程(亦即UI线程),从而实现工作线程对UI的更新处理,最终实现异步消息的处理。如此,当多个线程并发更新UI的同时,可以保证线程安全。当然,Handler在Android系统中还可以完成许多其他任务,例如Activity根据Handler发送的消息内容决定回调相应的生命周期函数等等。

    二、Handler消息传递机制原理

    Handler机制中的核心类总共有3个,分别是处理器类(Handler)、循环器类(Looper)、消息队列(MessageQueue),它们之间的关系如下图:


    示意图.png
    核心方法.png

    1.Handler.java

    /**
     * 仅贴出关键代码
     */
    public class Handler {
        ......
        final Looper mLooper;
        final MessageQueue mQueue;
    
        public void handleMessage(Message msg) {
        }
    
        public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    
        public Handler() {
            this(null, false);
        }
    
        public Handler(android.os.Handler.Callback callback, boolean async) {
            ......
            // 获取当前线程的Looper对象,若线程无Looper对象则抛出异常
            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                        "Can't create handler inside thread that has not called Looper.prepare()");
            }
            // 绑定消息队列对象(MessageQueue)
            mQueue = mLooper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }
    
        public final boolean post(Runnable r)
        {
            return  sendMessageDelayed(getPostMessage(r), 0);
        }
    
        public final boolean sendMessage(Message msg)
        {
            return sendMessageDelayed(msg, 0);
        }
    
        private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
        }
        ......
    }
    

    当我们使用无参构造方法新建一个Handler实例,这个无参构造方法会调用有参的构造方法。在构造过程中,有个重要的语句mLooper = Looper.myLooper(),会将当前线程ThreadLocal对象中储存的Looper对象赋值给Handler对象的成员变量mLooper,从而Handler绑定了Looper对象所绑定的线程(因为Looper对象本已绑定了对应线程)。所以,当创建Handler对象时,通过构造方法自动关联当前线程的Looper对象以及对应的消息队列对象(MessageQueue),从而自动绑定了实现创建Handler对象操作的线程。

    注意:在进行消息分发时,即dispatchMessage(msg),会进行发送方式的判断:
    如果msg.callback属性不为空,则代表使用了post(Runnable r)发送消息,则直接回调Runnable对象里复写的run();
    如果msg.callback属性为空,则代表使用了sendMessage(Message msg)发送消息,则回调复写的handleMessage(msg)

    2.Looper.java

    /**
     * 仅贴出关键代码
     */
    public final class Looper{
      ......
      static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
      final MessageQueue mQueue;
      final Thread mThread;
      ......
      public static Looper myLooper(){
            return sThreadLocal.get();
      }
      private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
      }
      
      private static void prepare(boolean quitAllowed) {
            //ThreadLocal是线程内部数据存储类
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(quitAllowed));
      }
      
      public static void prepareMainLooper() {
            prepare(false); 
            synchronized (Looper.class) {
                if (sMainLooper != null) {
                    throw new IllegalStateException("The main Looper has already been                               prepared.");
                }
                sMainLooper = myLooper();
            }
      }
    
      public static void loop() {
            final Looper me = myLooper();
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            final MessageQueue queue = me.mQueue;
            for (;;) {
                Message msg = queue.next();
                if (msg == null) {
                    return;
                }
                msg.target.dispatchMessage(msg);
                msg.recycleUnchecked();
                ......
            }
        }
      ......
    }
    

    prepare()方法,需在子线程中手动调用。先判断sThreadLocal.get()获取的Looper对象是否为null,如果不为空则抛出异常,表明Looper.prepare()方法不能被调用两次,亦即一个线程中只能对应1个Looper对象。

    prepareMainLooper()方法,创建主线程时会自动调用ActivityThread的静态main()方法,从而会调用Looper.prepareMainLooper()为主线程生成1个Looper对象,同时也会生成其对应的MessageQueue对象。

    loop()方法,消息循环,即从消息队列中获取消息、分发消息到Handler。主线程的消息循环不允许退出,即无限循环。子线程的消息循环允许退出,调用消息队列MessageQueue的quit()方法。loop()方法执行之前必须保证当前线程有Looper对象,即对于子线程而言,执行loop()方法之前必须先执行prepare()方法。loop()方法里面的消息循环通过无限for循环实现,由MessageQueue的next()方法取出消息对象Message,然后再将这个消息交给消息对象msg的target属性处理,这个的target属性实际上就是handler对象(可通过查看Handler源码中的enqueueMessage方法验证)。
    总结:主线程的Looper对象自动生成,不需手动创建。子线程的Looper对象则需手动通过Looper.prepare()创建。在子线程若不手动创建Looper对象,则无法创建Handler对象。Looper和MessageQueue对象创建完成后,通过Looper.loop()方法进入消息循环。

    引申:Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
    链接:https://www.zhihu.com/question/34652589/answer/90344494
    这里涉及线程,先说说说进程/线程,进程:每个app运行时前首先创建一个进程,该进程是由Zygote fork出来的,用于承载App上运行的各种Activity/Service等组件。进程对于上层应用来说是完全透明的,这也是google有意为之,让App程序都是运行在Android Runtime。大多数情况一个App就运行在一个进程中,除非在AndroidManifest.xml中配置Android:process属性,或通过native代码fork进程。
    线程:线程对应用来说非常常见,比如每次new Thread().start都会创建一个新的线程。该线程与App所在进程之间资源共享,从Linux角度来说进程与线程除了是否共享资源外,并没有本质的区别,都是一个task_struct结构体,在CPU看来进程或线程无非就是一段可执行的代码,CPU采用CFS调度算法,保证每个task都尽可能公平的享有CPU时间片。
    有了这么准备,再说说死循环问题:对于线程既然是一段可执行的代码,当可执行代码执行完成后,线程生命周期便该终止了,线程退出。而对于主线程,我们是绝不希望会被运行一段时间,自己就退出,那么如何保证能一直存活呢?简单做法就是可执行代码是能一直执行下去的,死循环便能保证不会被退出,例如,binder线程也是采用死循环的方法,通过循环方式不同与Binder驱动进行读写操作,当然并非简单地死循环,无消息时会休眠。但这里可能又引发了另一个问题,既然是死循环又如何去处理其他事务呢?通过创建新线程的方式。
    真正会卡死主线程的操作是在回调方法onCreate/onStart/onResume等操作时间过长,会导致掉帧,甚至发生ANR,looper.loop本身不会导致应用卡死。

    三、Handler机制的使用

    1.使用Handler.sendMessage()

    (1)内部类

    public class MainActivity extends AppCompatActivity {
    
        private Handler mHandler;
    
        class MyHandler extends Handler {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 1:
                        Toast.makeText(MainActivity.this, "执行了线程1的UI操作", Toast.LENGTH_LONG).show();
                        break;
                    case 2:
                        Toast.makeText(MainActivity.this, "执行了线程2的UI操作", Toast.LENGTH_LONG).show();
                        break;
                }
            }
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mHandler = new MyHandler();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Message message1 = Message.obtain();
                    message1.what = 1;
                    message1.obj = "Hello";
                    mHandler.sendMessage(message1);
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Message message2 = Message.obtain();
                    message2.what = 2;
                    message2.obj = "Hi";
                    mHandler.sendMessage(message2);
                }
            }).start();
        }
    }
    

    (2)匿名内部类

    public class MainActivity extends AppCompatActivity {
    
        private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 1:
                        break;
                    case 2:
                        break;
                }
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Message message1 = Message.obtain();
                    message1.what = 1;
                    message1.obj = "Hello";
                    mHandler.sendMessage(message1);
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Message message2 = Message.obtain();
                    message2.what = 2;
                    message2.obj = "Hi";
                    mHandler.sendMessage(message2);
                }
            }).start();
        }
    }
    

    2.使用Handler. post()

    public class MainActivity extends AppCompatActivity {
    
        private Handler mHandler = new Handler();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "执行了线程1的UI操作", Toast.LENGTH_LONG).show();
                        }
                    });
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "执行了线程2的UI操作", Toast.LENGTH_LONG).show();
                        }
                    });
                }
            }).start();
        }
    }
    

    3.主线程向子线程发送消息

    public class MainActivity extends AppCompatActivity {
    
        private Handler mHandler;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            new LooperThread().start();
    
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    Message message = Message.obtain();
                    message.what = 1;
                    message.obj = "Hello";
                    mHandler.sendMessage(message);
                }
            }, 1000);
        }
    
        class LooperThread extends Thread {
    
            public void run() {
                Looper.prepare();
    
                mHandler = new Handler() {
                    public void handleMessage(Message msg) {
                        switch (msg.what) {
                            case 1:
                                Log.e("MainActivity", "message come");
                                break;
                        }
                    }
                };
    
                Looper.loop();
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Android Handler消息传递机制

          本文链接:https://www.haomeiwen.com/subject/lnmfpftx.html