加入收藏 | 设为首页 | 会员中心 | 我要投稿 东莞站长网 (https://www.0769zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长资讯 > 评论 > 正文

Android消息机制Handler,有必要再讲一次

发布时间:2019-07-28 07:42:38 所属栏目:评论 来源:Engineers
导读:副标题#e# 我们在日常开发中,总是不可避免的会用到 Handler,虽说 Handler 机制并不等同于 Android 的消息机制,但 Handler 的消息机制在 Android 开发中早已谙熟于心,非常重要! 通过本文,你可以非常容易得到一下问题的答案: Handler、Looper、Message
副标题[/!--empirenews.page--]

我们在日常开发中,总是不可避免的会用到 Handler,虽说 Handler 机制并不等同于 Android 的消息机制,但 Handler 的消息机制在 Android 开发中早已谙熟于心,非常重要!

Android消息机制Handler,有必要再讲一次

通过本文,你可以非常容易得到一下问题的答案:

  1. Handler、Looper、Message 和 MessageQueue 的原理以及它们之间的关系到底是怎样的?
  2. MessageQueue 存储结构是什么?
  3. 子线程为啥一定要调用 Looper.prepare() 和 Looper.loop()?

Handler 的简单使用

相信应该没有人不会使用 Handler 吧?假设在 Activity 中处理一个耗时任务,需要更新 UI,简单看看我们平时是怎么处理的。

  1. override fun onCreate(savedInstanceState: Bundle?) { 
  2.  super.onCreate(savedInstanceState) 
  3.  setContentView(R.layout.activity_main3) 
  4.  // 请求网络 
  5.  subThread.start() 
  6. override fun onDestroy() { 
  7.  subThread.interrupt() 
  8.  super.onDestroy() 
  9. private val handler by lazy(LazyThreadSafetyMode.NONE) { MyHandler() } 
  10. private val subThread by lazy(LazyThreadSafetyMode.NONE) { SubThread(handler) } 
  11. private class MyHandler : Handler() { 
  12.  override fun handleMessage(msg: Message) { 
  13.  super.handleMessage(msg) 
  14.  // 主线程处理逻辑,一般这里需要使用弱引用持有 Activity 实例,以免内存泄漏 
  15.  } 
  16. private class SubThread(val handler: Handler) : Thread() { 
  17.  override fun run() { 
  18.  super.run() 
  19.  // 耗时操作 比如做网络请求 
  20.  // 网络请求完毕,咱们就得哗哗哗通知 UI 刷新了,直接直接考虑 Handler 处理,其他方案暂时不做考虑 
  21.  // 第一种方法,一般这个 data 是请求结果解析的内容 
  22.  handler.obtainMessage(1,data).sendToTarget() 
  23.  // 第二种方法 
  24.  val message = Message.obtain() // 尽量使用 Message.obtain() 初始化 
  25.  message.what = 1 
  26.  message.obj = data // 一般这个 data 是请求结果解析的内容 
  27.  handler.sendMessage(message) 
  28.  // 第三种方法 
  29.  handler.post(object : Thread() { 
  30.  override fun run() { 
  31.  super.run() 
  32.  // 处理更新操作 
  33.  } 
  34.  }) 
  35.  } 

上述代码非常简单,因为网络请求是一个耗时任务,所以我们新开了一个线程,并在网络请求结束解析完毕后通过 Handler 来通知主线程去更新 UI,简单采用了 3 种方式,细心的小伙伴可能会发现,其实第一种和第二种方法是一样的。就是利用 Handler 来发送了一个携带了内容 Message 对象,值得一提的是:我们应该尽可能地使用 Message.obtain() 而不是 new Message() 进行 Message 的初始化,主要是 Message.obtain() 可以减少内存的申请。

受到大家在前面文章提出的建议,我们就尽量地少贴一些源码了,大家可以直接很容易发现,上述的所有方法最终都会调用这个方法:

  1. public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 
  2.  MessageQueue queue = mQueue; 
  3.  if (queue == null) { 
  4.  RuntimeException e = new RuntimeException( 
  5.  this + " sendMessageAtTime() called with no mQueue"); 
  6.  Log.w("Looper", e.getMessage(), e); 
  7.  return false; 
  8.  } 
  9.  return enqueueMessage(queue, msg, uptimeMillis); 
  10. private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { 
  11.  msg.target = this; 
  12.  if (mAsynchronous) { 
  13.  msg.setAsynchronous(true); 
  14.  } 
  15.  return queue.enqueueMessage(msg, uptimeMillis); 

上面的代码出现了一个 MessageQueue,并且最终调用了 MessageQueue#enqueueMessage 方法进行消息的入队,我们不得不简单说一下 MessageQueue 的基本情况。

MessageQueue

(编辑:东莞站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读