Handler
Handler可以说是Android框架里面很精髓的一部分了,面试必问,用的也最多
Handler是什么?
提到Handler大家一定不陌生,我们经常用它来切换线程,或者是说做一些延时任务等等。最常用的地方可能就是在网络请求中去切换到主线程中去操作UI。为什么要切换到主线程去操作UI呢?在这之前我们知道在Android里面所有的View都是线程不安全的,意思就是你不能多线程去操作UI,这是Android不允许的,它规定了你只能在主线程去操作UI。
总结一句话就是:Handler就是用于线程间通信,解决子线程无法访问UI的问题
Handler的几种常见使用方法
注意:Handler的无参构造已经弃用
1.作为内部类
作为内部类的使用方法相信大家在熟悉不过了:
class MainActivity : AppCompatActivity() {
private val mBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }
private val myHandler = MyHandler()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mBinding.button.setOnClickListener {
myHandler.sendEmptyMessage(0);
}
}
inner class MyHandler() : Handler(Looper.myLooper()!!) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
Toast.makeText(this@MainActivity, "处理消息", Toast.LENGTH_SHORT).show()
}
}
}
2.作为匿名内部类
class MainActivity : AppCompatActivity() {
private val mBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }
private val myHandler = object :Handler(Looper.myLooper()!!){
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
Toast.makeText(this@MainActivity, "处理消息", Toast.LENGTH_SHORT).show()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(mBinding.root)
mBinding.button.setOnClickListener {
myHandler.sendEmptyMessage(0);
}
}
}
作为匿名内部类和作为内部类的方法差不多,不过是把内部类的名字去掉了。
3.作为静态内部类
作为静态类的使用方法就是把内部类变为静态类:
class MainActivity : AppCompatActivity() {
private val mBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }
private val myHandler = MyHandler(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(mBinding.root)
mBinding.button.setOnClickListener {
myHandler.sendEmptyMessage(0)
}
}
class MyHandler(context: Context) : Handler(Looper.myLooper()!!) {
private val weakContext = WeakReference(context)
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
Toast.makeText(weakContext.get(), "处理消息", Toast.LENGTH_SHORT).show()
}
}
}
在kotlin中不加inner关键字的内部类默认就是静态的。这里为什么用WeakReference去引用context?这是防止内存泄漏,等会说。
Handler的内存泄漏问题
内存泄漏可以说是面试必问的,也是我们开发者所必须熟知的。
什么是内存泄漏?
那么什么是内存泄漏呢?就是程序中已经动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费。
简单来说就是一个对象该被回收却没有被回收,造成了内存浪费。最常见的就是长生命周期引用短生命周期。
比如你的activity实例被一个静态变量引用,当你的activity销毁的时候,activity对象应该被回收,而静态变量会一直存在程序中,所以JVM会认为你的activity被一个静态变量引用,认为它还有用,它就不会回收activity实例,从而造成内存泄漏。
整理了面试过程中被问及的Handler相关的知识点。会涉及到很多细节知识,大家可以作为面试参考了解一下。
如需要完整版 请点击此处免费获取
- Handler基础
- 获取Message实例的方式?为什么要用obtain的方式获取?
- Looper死循环为什么不会导致应用卡死?
- 如何保证线程和Looper的一对一关系的?
- handler是如何发送延迟消息的?
- 如果想要在子线程中new Handler要做些什么准备?
- Handler内存泄露
- 如何监控handler中的消息?
- 异步消息、同步屏障
- 异步消息在源码中的应用
- 如何外部发送一个异步消息
- IdleHandler
- …