Handler学习总结

Handler学习总结

讲解handler之前,我们要认识到这一点:在activity创建时候,系统会给我们创建一个activity main thread ,这也就是我们所说的UI线程或者Main线程。

要学习handler,就得了解几个重要的关系。
Handler:接收和发送消息,更新UI操作
Looper:负责接收Handler发送的消息,将消息存放在MessageQueue里面,通过Looper.loop()轮询取出消息。
Message:Handler发送消息的内容,存放在message里面。
MessageQueue:存储消息的容器,类似一个消息栈。

Handler的几个用法:

//handler.post 立即发送消息
 handler.post(new Runnable() {
            @Override
            public void run() {

            }
        });
//handler.postDelayed 延迟时间发送消息
 handler.postDelayed(new Runnable() {
            @Override
            public void run() {

            }
        },0);
//handler.send 立即发送消息
handler.sendEmptyMessage(0);
//handler.sendMessageDelayed  延时发送消息
handler.sendMessageDelayed(new Message(),0);

还要清楚这样一点,Handler发送的消息都是要自己接收的,发送到looper的消息通过looper.loop()方法从messageQueue取出message之后,通过Handler里面的handleMessage()这个方法来获取消息。

创建一个handler,如果没有说明具体绑定looper,那就是绑定在UI线程的Looper上的。我们可以看一下源码

在new 一个Handler时候:

 /**
     * Default constructor associates this handler with the {@link Looper} for the
     * current thread.
     *
     * If this thread does not have a looper, this handler won't be able to receive messages
     * so an exception is thrown.
     */
    public Handler() {
        this(null, false);
    }

然后看看this的方法:

public Handler(Callback callback, boolean async) {
     if (FIND_POTENTIAL_LEAKS) {
 final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

看到有一行是 mLooper = Looper.myLooper();说明Handler是绑定在Looper.myLooper(),也就是Ui线程上的。

如果我们开一个子线程,给Handler创建的时候给它一个looper对象

final HandlerThread handlerThread = new HandlerThread("ChildThread");
        handlerThread.start();

        childHandler = new Handler(handlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                Log.e("Child_Thread------>",String.valueOf(childHandler.getLooper().getThread()));
                handler.sendEmptyMessageDelayed(0, 1000);
            }
        };

先写一个子线程HandlerThread,然后获取handlerThread的looper来创建一个子线程的Handler,然后跟主线程的Handler相互通信。

Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Log.e("UI_Thread------>", String.valueOf(handler.getLooper().getThread()));
            childHandler.sendEmptyMessageDelayed(0, 1000);
        }
    };

查看打印的日志就会发现线程名称是不一样的,一个是Mian线程,一个是我们自己定义的ChildThread线程。

这里解释一下为啥要用HandlerThread创建线程呢,我们来看一下源码:

public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

在获取handlerThread.getLooper()时候发现,如果Looper是空的,需要等待,等待创建完Looper之后,在返回创建好的Looper。这样或许还显示不出来HandlerThread的好处,我们举个这样的例子:

首先自定义一个子线程:

class MyThread extends Thread {

        private Handler childHandler;

        public Looper looper;

        @Override
        public void run() {
            Looper.prepare();

            looper = Looper.myLooper();

            childHandler = new Handler(looper) {
                @Override
                public void handleMessage(Message msg) {

                }
            };

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            Looper.loop();

        }
    }

然后让子线程暂停一秒模拟线程并发的情况。
然后调用子线程,把子线程的looper绑定到Handler中

 MyThread thread = new MyThread();
        thread.start();

        Handler handler = new Handler(thread.looper) {

            @Override
            public void handleMessage(Message msg) {

            }
        };

        handler.sendEmptyMessage(0);

运行程序,会发现有一个NullPointerException: Attempt to read from field ‘android.os.MessageQueue android.os.Looper.mQueue’ on a null object reference的异常,说明在创建Handler时候,Looper是个空的,所以这里在防止线程并发时候,就需要引入HandlerThread这个类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值