Handler

Handler

Handler是什么:
Handler通常被我们用来做主线程与子线程之间的通信工具,他的应用非常广泛,可以说只要有异步线程与
主线程通信的地方一定会有Handler.

Handler运行机制:

1.首先在主线程创建一个Handler对象 ,并重写handleMessage方法。
2.然后当在子线程中需要进行更新UI的操作,我们就创建一个Message对象,并通过handler发送这条消息出去。
3.之后这条消息被加入到MessageQueue队列中等待被处理,通过Looper对象会一直尝试从Message Queue中取出待处理的
4.消息,最后分发会Handler的handlerMessage方法中,然后进行相应的处理。

Handler的原理是什么:
android提供了Handler和Looper来满足线程之间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象
之间的消息交换(MessageExchange)。
1.Looper:一个线程可以产生一个Looper对象,由他来管理此线程里的MessageQueue(消息队列)
2.Handler:你可以构造Handler独享来与Looper沟通,以便push新消息到MessageQueue里,或者接收
Looper从Message Queue取出来所发送的消息。
3.Message Queue(消息队列):用来存放线程放入的消息、
4.线程:Ulthread 通常就是main thread,而Android启动程序时会替他简历一个MessageQueue。

Handler有什么作用:
更新UI,发送消息、处理消息

为什么使用handler、MessageQueue、Looper?
主线程无法进行时间比较长的任务,所以需要子线程进行处理,然而子线程无法进行UI的界面更新,所以
我们需要使用hanler来传递消息给主线程,让其完成ui的更新。由于主线程和子线程进行不同的时间工作,
所以需要用MessageQueue来存放子线程的消息,Looper取出消息交给主线程响应。

Android为什么要设计只能通过Handler机制更新UI呢?
最根本的目的就是解决多线程并发问题。 假如在一个Activity当中,有多个线程去更新UI,并且都没有加锁机制,
那么肯定会照成更新界面错乱。 如果对更新UI的操作都进行了加锁处理的话那么肯定会照成性能下降的问题
所以出于对以上问题的考虑,android给我们提供了一套更新UI的机制,我们只需要遵循这样的机制就行了,
而根本不用去关心多线程问题,所有的更新UI的操作,都是在主线程的消息队列当中去轮询处理的。

Handler怎么用:
在使用Handler之前必须要调用Looper.prepare()这句代码,这句代码的作用是将Looper与当前的线程进行
绑定,在实例化Handler的时候,通过Looper.myLooper()获取Looper,然后再获得Looper中的MessageQueue。
在子线程中调用Handler的sendMessage方法就是将Message放入MessageQueue中,然后调用Looper.loop()方法
来从MessageQueue中取出Message,在取到Message的时候,执行 msg.target.dispatchMessage(msg);
这句代码,这句代码就是从当前的Message中取出Handler然后执行Handler的handleMessage方法。

Android中更新UI的几种方式:

使用Handler时候遇到的问题?

Android中子线程真的不能更新UI吗?
是系统不建议在子线程更新ui:因为Android的UI访问是没有加锁的,多个线程可以同时访问更新操作
同一个UI控件。也就是说访问UI的时候,android系统当中的控件都不是线程安全的,这将导致在多
线程模式下,当多个线程共同访问更新操作同一个UI控件时容易发生不可控的错误,而这是致命的。
所以Android中规定只能在UI线程中访问UI,这相当于从另一个角度给Android的UI访问加上锁,一个伪锁。

一个Thread可以有几个Looper?几个Handler?
只能有一个Looper,不然调用Looper.prepare()会抛出运行时异常,提示“Only one Looper may be created per thread”
可以创建无数个Handler,但是他们使用的消息队列都是同一个,也就是同一个Looper

可以在子线程直接new一个Handler吗?那该怎么做?
当我们在主线程中创建Handler对象的时候没有问题,是因为主线程会自动调用Looper.prepare()
方法去给当前主线程创建并设置一个Looper对象,随意在Handler构造函数中从当前线程的对象身上拿到这个Looper。
但是子线程中并不会自动调用这个方法,所以要想在子线程中创建Handler对象就必须在创建之前手动调用Looper.prepare()方法,否则就会报错。

Message可以如何创建?哪种效果更好,为什么?
Message msg = new Message();这种就是直接初始化一个Message对象,没有什么特别的。
Message msg2 = Message.obtain();从整个Messge池中返回一个新的Message实例,通过obtainMessage能避免重复Message创建对象。
Message msg1 = handler1.obtainMessage(); 第二种跟第三种其实是一样的,都可以避免重复创建Message对象,所以建议用第二种或者第三种任何一个创建Message对象。

主线程中Looper的轮询死循环为何没有阻塞主线程?
因为Android 的是由事件驱动的,looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说
Activity的生命周期都是运行在 Looper.loop() 的控制之下,如果它停止了,应用也就停止了。
只能是某一个消息或者说对消息的处理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它。
也就说我们的代码其实就是在这个循环里面去执行的,当然不会阻塞了。如果某个消息处理时间过长,
比如你在onCreate(),onResume()里面处理耗时操作,那么下一次的消息比如用户的点击事件不能处理了
,整个循环就会产生卡顿,时间一长就成了ANR。所以Looer.loop()方法可能会引起主线程的阻塞,
但只要它的消息循环没有被阻塞,能一直处理事件就不会产生ANR异常。

使用Hanlder的postDealy()后消息队列会发生什么变化?

点击页面上的按钮后更新TextView的内容,谈谈你的理解?
1、需要在主线程更新UI,不能在子线程更新UI(Only the original thread that created a view hiearchy can touch its views);

2、需要在子线程创建Handler,并且需要为这个Handler准备Looper,否则会报错(Can't create handler inside thread
that has not called Looper.prepare() );

3、Handler使用不当可能引起的内存泄漏(OOM,在所有的OOM问题,因为handler使用不当而导致OOM是最多的);

4、Message的优化(最好使用Handler.obtainMessage() ,直接new Message会带来内存的消耗 );

5、在Handler把消息处理完了以后,但是页面销毁了,这个时候可能Handler会更新UI,但是比如
textview、imageview之类的资源引用不见了,就会抛出NullPointer Exception异常;

生产者-消费者设计模式懂不?
某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、
线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。在生产者
与消费者之间在加个缓冲区,我们形象的称之为仓库,生产者负责往仓库了进商品,而消费者负责从仓库
里拿商品,这就构成了生产者消费者模式。

Handler是如何完成子线程和主线程通信的?

关于ThreadLocal,谈谈你的理解?
跟HashMap类似,为什么不直接用HashMap呢?
原因:
1、HashMap太大了,太臃肿了。ThreadLocal的key值只有Thread,而HashMap的key值则可以
是string、int等数据类型,我们可以不用考虑这些数据类型;
2、线程隔离:我们的线程是系统中唯一的,用ThreadLocal来管理这些唯一的线程和其
对应的value值会非常方便,
3、ThreadLocal参照了HashMap,简化了HashMap,便于我们使用。

享元设计模式有用到吗?
在new Message的时候我们不直接new,而是调用obtain()方法,就是使用到了享元设计模式。

享元模式主要解决的就是减少相同对象的创建,以便节省内存空间,从而提高系统的性能。

Handler 与 Looper 的关联:
实际上我们在实例化 Handler 的时候 Handler 会去检查当前线程的 Looper 是否存在,如果不存在则会报异常,也就是说在创建
Handler 之前一定需要先创建 Looper 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值