Android Handler消息传递机制

2018-07-10  本文已影响0人  lxbnjupt

一、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();
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读