学习总结:Handler机制

Handler

安卓为了保证线程的安全,规定只能在主线程更新UI界面,但是由于开发者在编写代码的过程中,经常需要开辟子线程处理耗时任务,并且需要更新UI,但是若是在子线程中更新UI又会报错,如果不使用子线程,直接在主线程执行耗时任务又会导致ANR。所以就引进了Handler机制,来实现子线程和主线程之间的通信。

流程

核心机制就是子线程通过Handler发送封装有数据的Message对象到MessageQueue里,随后Looper通过循环,不断取出在MessageQueue里的Message对象,分发给处理Message的handler。

用法

1、在主线程实例化Handler对象,并重写handlerMessage()方法。 2、在子线程中创建消息对象,并发送出去。

private Handler mHandler = new Handler(){
          
   
        @Override
        public void handleMessage(Message msg) {
          
   
            //接收到消息之后,应该实现的业务逻辑。
            switch (msg.what){
          
   
                case 1:
                    Toast.makeText(MainActivity.this, "接收到子线程传来的消息", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    break;
            }
        }
    };
new Thread(new Runnable() {
          
   
            @Override
            public void run() {
          
   
                //开辟子线程执行耗时任务
                //随后创建对象
                Message msg = Message.obtain();
                msg.what = 1;
                mHandler.sendMessage(msg);//发送信息
            }
        });

注意

1、没有Looper的线程不能创建Handler对象。主线程在创建时会自动运行prepareMainLooper(),此时主线程就拥有了Looper,并绑定了MessageQueue,所以可以创建Handler对象。 2、如果想要让一个线程可以创建Handler对象,那么首先需要调用Looper.prepare()创建Looper。 3、一个线程只能有一个Looper和一个MessageQueue,但是可以有多个Hanlder。 4、Looper的循环并不会导致线程阻塞,因为在没有对象可以取出的时候,它会休眠 5、使用Handler会引起内存泄漏的原因主要是: 当一个Activity新建了Handler发送了一条延时消息之后,假如这个Activity被finish了,但是这条消息仍然存活在消息队列里,而这个消息持有对Handler的引用,而Handler又持有对Activity的引用,就导致这个Activity不会被回收,造成内存泄漏。 解决方法:把继承的Handler类声明为静态内部类,因为静态内部类不会持有对外部类的引用。但是假如你需要引用外部类的方法,那么可以在非静态内部类里持有对外部类的弱引用。或者在Activity结束的时候,清空消息队列里的信息。 6、Handler发送消息的sendMessage()和post()的区别在于,使用sendMessage()发送的话,需要重写handlerMessage()来处理,而使用post()的话,因为post()传入的是一个runnable,所以可以直接执行runnable里的语句,并没有开启一个新线程。是哪个handler发送的,就在哪个handler所在的线程执行。 7、创建消息实例可以直接new一个Message对象,但是推荐使用Message.obtain()方法,因为这个方法可以先从消息池中看看有没有可用的实例,如果有就直接用,如果没有就才new一个。通过使用这个方法可以提高效率。 8、idleHandler是一个接口,作用在于在消息队列空闲的时候可以调用他的函数来执行一些不耗时操作,优化性能。 9、消息屏障,作用在于阻挡它的时间之后的同步消息,使得异步消息优先执行。调用postSyncBarrier()插入,removeSyncBarrier()删除。它会阻塞所有的在他之后进入的同步消息,所以如果删除了之后要根据是否因为消息屏障而阻塞,还决定是否要唤醒线程。 10、一个线程可以有多个handler,所以每一条发出去的消息都会有一个target值,用来表示是哪个handler发出去的。handler在哪个线程创建的,就关联了哪个线程的Looper,但是也可以传入指定的Looper

经验分享 程序员 微信小程序 职场和发展