Android线程间通信 Handler使用详解

目录
  • 前言
  • 01、定义
  • 02、使用
    • 第一步、创建
    • 第二步、发送消息
      • 第一种是 post(Runnable)
      • 第二种是 sendMessage(Message)
    • 第三步、处理消息
  • 03、结语

前言

Handler,可谓是面试题中的一个霸主了。在我《面试回忆录》中,几乎没有哪家公司,在面试的时候是不问这个问题的。简单一点,问问使用流程,内存泄漏等问题。复杂一点,纠其源码细节和底层 epoll 机制来盘你。所以其重要性,不言而喻了吧。

那么今天让我们来揭开 Handler 的神秘面纱。为了读者轻松易读不烧脑,本系列文章按照使用篇,源码篇,面试篇来分篇浅析。

01、定义

在了解如何使用前,我们先来看看什么是 Handler ?

A Handler allows you to send and process and Runnable objects associated with a thread's .

可以用 Handler 发送并且处理与线程有关的 Runnable 对象。

这听起来,可能还有点迷惑。那么讲一个常见的场景来引出 Handler 吧。你接到了一个需求:有一个文件列表,点击文件后,开始下载该文件,下载完成后,在列表中对应文件上加上已下载的标识。

下载是一个耗时的动作,为了不引起 ANR(Application not response),我们通常需要通过子线程去完成这任务。但通常情况下(有特殊情况),我们又不能在非主线程中去更新 UI,所以就需要进行线程间通信。而 Handler 便发挥其作用了——进行线程间通信。

02、使用

第一步、创建

在创建 Handler 的时候,需要有注意一下是在主线程还是子线程。

//主线程
private val mHandler: Handler = object : Handler(Looper.getMainLooper()) {
    override fun handleMessage(msg: Message) {
        when (msg.what) {
            1 -> {}
        }
    }
}
//子线程
Thread {
    Looper.prepare()
    val handler = object : Handler() {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                1 -> {}
            }
        }
    }
    handler.sendEmptyMessage(1)
    Looper.loop()
}.start()

在主线程创建我们无需调用 Looper.prepare()Looper.loop()

在子线程需要手动调用者两个方法。至于为什么主要是主线的这两个方法,在应用入口 main() 中系统帮我们完成了,具体见后续原理篇。

第二步、发送消息

发送消息有两大类方式(此处忽略定时和延迟发送)

第一种是 post(Runnable)

// 未简化写法,为了更好理解
mHandler.post(object :Runnable{
    override fun run() {
        // TODO  具体业务逻辑
    }
})

第二种是 sendMessage(Message)

val msg = Message()
msg.what = 1
msg.obj = "Quincy"
mHandler.sendMessage(msg)

但其实两者本质上是没有区别的。因为上面两种方式最后都调用了 sendMessageDelayed(),只是源码上帮我们把 Runnable 包装成了一个 Message。具体看下一篇,源码篇。

第三步、处理消息

处理消息,并非简单地在 handleMessage() 中处理即可,这还是要分情况的。为了方便分析,我们先浅浅窥探一下处理消息的源码

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg); // 注释1
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return; //注释2
            }
        }
        handleMessage(msg); //注释3
    }
}

注意上面三点注释,它们之间的关系。如果 Message.callback 不为空,即通过 post() 发送消息的,则调用 handleCallback(Message)

private static void handleCallback(Message message) {
        message.callback.run();
    }

否则,如果 mCallback 不为空且拦截了消息,则不再调用 handleMessage()

private val handler = object : Handler(object : Callback {
    override fun handleMessage(msg: Message): Boolean {
        if (msg.what == 1) {
            return true//不会调用注释3
        }
        return false//会调用注释3
    }
}) {
    override fun handleMessage(msg: Message) {
        when (msg.what) {
            1 -> {}
        }
    }
}

否则将回调。

private val mHandler: Handler = object : Handler() {
    override fun handleMessage(msg: Message) {
        when (msg.what) {
            1 -> {}
        }
    }
}

03、结语

以上就是 Handler 的使用篇,主要是分享了基础的使用方法,以此作为源码篇的铺垫。最后提出几个问题,大家可以带着问题去看看源码。下一篇文章,我们将会揭开谜底。

  • 一个线程中有多个 Handler ,但只有 1 个 Looper 和 1个 MessageQueue。哪在分发消息的时候,怎么知道发个哪一个 Handler 呢?
  • Looper 中有多少个 for( ; ; ),分别的作用是什么呢?
  • 消息被处理后,Message 是被怎么处理的呢?
  • Handler 为什么会引起内存泄漏?
  • Handler 中有 Looper 的死循环,为什么没有卡死呢?(我认为就是要卡“死”,正是因为它我们的程序才没有退出)

以上就是Android线程间通信 Handler使用详解的详细内容,更多关于Android线程通信Handler的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android Handler runWithScissors 梳理流程解析

    目录 前言 runWithScissors 梳理流程 存在的问题 总结 前言 看 WMS 代码的时候看到了 Handler.runWithScissors 方法,所以来恶补一下 public static WindowManagerService main(final Context context, final InputManagerService im,final boolean showBootMsgs, final boolean onlyCore, WindowManagerPoli

  • Android Handler的使用详解

    在Android开发中,我们经常会遇到这样一种情况:在UI界面上进行某项操作后要执行一段很耗时的代码,比如我们在界面上点击了一个"下载"按钮,那么我们需要执行网络请求,这是一个耗时操作,因为不知道什么时候才能完成.为了保证不影响UI线程,所以我们会创建一个新的线程去执行我们的耗时的代码.当我们的耗时操作完成时,我们需要更新UI界面以告知用户操作完成了.所以我们可能会写出如下的代码: package ispring.com.testhandler; import android.app.

  • Android线程间通信Handler源码详解

    目录 前言 01. 用法 02.源码 03.结语 前言 在[Android]线程间通信 - Handler之使用篇主要讲了 Handler 的创建,发送消息,处理消息 三个步骤.那么接下来,我们也按照这三个步骤,从源码中去探析一下它们具体是如何实现的.本篇是关于创建源码的分析. 01. 用法 先回顾一下,在主线程和非主线程是如何创建 Handler 的. //主线程 private val mHandler: Handler = object : Handler(Looper.getMainLo

  • Android开发中Google为什么不让用Handler的runWithScissors()

    目录 一.序 二.Handler.runWithScissors() 2.1 runWithScissors() 2.2 Framework 中的使用 三.runWithScissors() 的问题 3.1 如果超时了,没有取消的逻辑 3.2 可能造成死锁 四.总结时刻 一.序 大家好,这里是承香墨影! runWithScissors() 是 Handler 的一个方法,被标记为 @hide,不允许普通开发者调用. 这个方法算是比较冷门,如果面试中被问及,面试者不知道时,通常面试官会换个问法:"

  • Android Handler使用案例详解

    什么是Handler? Handler可以发送和处理消息对象或Runnable对象,这些消息对象和Runnable对象与一个线程相关联.每个Handler的实例都关联了一个线程和线程的消息队列.当创建了一个Handler对象时,一个线程或消息队列同时也被创建,该Handler对象将发送和处理这些消息或Runnable对象. handler类有两种主要用途: 执行Runnable对象,还可以设置延迟. 两个线程之间发送消息,主要用来给主线程发送消息更新UI. 为什么要用Handler 解决多线程并

  • android studio的Handler简单实例代码

    实现:EditText输入消息,通过按钮选择发送给主线程或者子线程: 以下有效果图.MainActivity.java代码和activity_main.xml代码 效果图: MainActivity.java代码 package huan.san.handleroneapp; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle;

  • Android线程间通信 Handler使用详解

    目录 前言 01.定义 02.使用 第一步.创建 第二步.发送消息 第一种是 post(Runnable) 第二种是 sendMessage(Message) 第三步.处理消息 03.结语 前言 Handler,可谓是面试题中的一个霸主了.在我<面试回忆录>中,几乎没有哪家公司,在面试的时候是不问这个问题的.简单一点,问问使用流程,内存泄漏等问题.复杂一点,纠其源码细节和底层 epoll 机制来盘你.所以其重要性,不言而喻了吧. 那么今天让我们来揭开 Handler 的神秘面纱.为了读者轻松易

  • 深入Android Handler与线程间通信ITC的详解

    在<Android Handler之消息循环的深入解析>中谈到了Handler是用于操作线程内部的消息队列,所以Handler可以用来线程间通信ITC,这种方式更加安全和高效,可以大大减少同步的烦恼,甚至都可以不用syncrhonized.线程间通讯ITC正常情况下函数调用栈都会生存在同一个线程内,想要把执行逻辑交换到其他线程可以新建一个Thread,然后start().另外一种方法就是用ITC,也即用消息队列来实现,线程需要把执行逻辑交到其他线程时就向另外的线程的消息队列发送一个消息,发送消

  • Android USB转串口通信开发实例详解

     Android USB转串口通信开发实例详解 好久没有写文章了,年前公司新开了一个项目,是和usb转串口通信相关的,需求是用安卓平板通过usb转接后与好几个外设进行通信,一直忙到最近,才慢慢闲下来,趁着这个周末不忙,记录下usb转串口通信开发的基本流程. 我们开发使用的是usb主机模式,即:安卓平板作为主机,usb外设作为从机进行数据通信.整个开发流程可以总结为以下几点: 1.发现设备 UsbManager usbManager = (UsbManager) context.getSystem

  • wxpython多线程防假死与线程间传递消息实例详解

    wxpython中启用线程的方法,将GUI和功能的执行分开. 网上关于python多线程防假死与线程传递消息是几年前的,这里由于wxpython和threading模块已经更新最新,因此给出最新修改代码,能在2017年最新版的python和模块中运行. 原来的publisher()和callafter都无法使用. 修改后的代码. import time import wx from threading import Thread from wx.lib.pubsub import pub cla

  • vue组件间通信子与父详解(二)

    接着vue组件父与子通信详解继续学习. 二.组件间通信(子组件传值给父组件) 通过事件的方式来完成数据的传输. ①在父组件中 定义一个方法,用来接收子组件所通过事件传来的值 methods:{ recvMsg:function(msg){ //参数msg就是子组件通过事件出来的数据 } } ②绑定事件处理函数 事件一般情况 都是自定义事件 <child-component @myEvent="recvMsg"></child-component> ③在子组件触发

  • Java并发编程线程间通讯实现过程详解

    在Java中线程间通讯有多种方式,我这里列出一些常用方式,并用代码的方式展示他们是如何实现的: 共享变量 wait, notify,notifyAll(这3个方法是Object对象中的方法,且必须与synchronized关键字结合使用) CyclicBarrier.CountDownLatch 利用LockSupport Lock/Condition机制 管道,创建管道输出流PipedOutputStream和管道输入流PipedInputStream 示例一: package com.zhi

  • Java线程间共享实现方法详解

    一.synchronize对象锁和类锁 synchronize为多线程关键字是一种同步锁,它可以修饰以下几种对象: 代码块:被修饰的代码块被称为同步代码块,作用的范围是{}里面的代码,作用的对象是调用这个代码块的对象 方法:被修饰的方法称为同步方法,作用的范围是整个方法,作用的对象是调用这个方法的对象 类:作用的范围是synchronize后面括号里的部分,作用的对象是当前这个类 1.对象锁 下面由一个栗子引入: public class TestSynchronize { //加了对象锁的方法

  • android实现线程间通信的四种常见方式

    1,通过Handler机制 主线程中定义Handler,子线程发消息,通知Handler完成UI更新,Handler对象必须定义在主线程中,如果是多个类直接互相调用,就不是很方便,需要传递content对象或通过接口调用. 另外Handler机制与Activity生命周期不一致的原因,容易导致内存泄漏,不推荐使用. private void one() { handler=new Handler(){ @Override public void handleMessage(Message msg

  • Android Handler机制详解原理

    Looper是整个跨线程通信的管理者 // 内部持有的变量如下: ThreadLocal<Looper> MainLooper Observer MessageQueue Thread 1.首先先回忆一下Handler怎么用 Android线程通信分为以下两种情况 1.子线程发消息给UI线程 2.UI线程发消息给子线程 3.子线程发消息给另个子线程 1.子线程发消息给UI线程 class FragmentContentActivity : AppCompatActivity() { val F

随机推荐