Android 消息机制之初识Handler [ 六 ]

Android 消息机制深入源码分析 [ 一 ]
Android 消息机制之 ThreadLocal 深入源码分析 [ 二 ]
Android 消息机制之 Looper 深入源码分析 [ 三 ]
Android 消息机制之 Message 与消息对象池的深入源码分析 [ 四 ]
Android 消息机制之 MessageQueue 深入源码分析 [ 五 ]
Android 消息机制之初识Handler [ 六 ]
Android 消息机制之 Handler 发送消息的深入源码分析 [ 七 ]
Android 消息机制之 MessageQueue.next() 消息取出的深入源码分析 [ 八 ]
Android 消息机制之消息的其他处理深入源码分析 [ 九 ]
Android 消息机制总结 [ 十 ]

前几章分解学习了 ThreadLocal, Looper, Message, MessageQueue 等相关的知识, 本章节开始正式学习 Android 中消息机制的重中之重 Handler. 那么让我们正式开始学习吧.

1. 什么是 Handler

  • Handler 是一个可以通过关联一个消息队列来发送和处理消息, 发送或处理 Runnable 对象的一个处理程序.
  • 每个 Handler 都关联一个单个的线程和消息队列. 当我们创建一个新的 Handler 的时候, 它就绑定到一个线程上或者线程上的消息队列, 从那个时候起, 这个 Handler 就将为这个消息队列提供消息或者 Runnable 对象处理消息队列释放出来的消息或者 Runnable 对象.

2. Handler 有什么用

  • 安排消息和 Runnable 对象在未来执行.
  • 将用户的一个动作放在不同的线程上执行.

3. 构造函数

Handler 的构造函数一共有七个, 六个是有参, 一个无参的, 所有的构造函数都为 public

  • 1.public Handler()
  • 2.public Handler(Callback callback)
  • 3.public Handler(Looper looper)
  • 4.public Handler(Looper looper, Callback callback)
  • 5.public Handler(boolean async)
  • 6.public Handler(Callback callback, boolean async)
  • 7.public Handler(Looper looper, Callback callback, boolean async)

这七个构造函数, 又将分为两类. 分别为两个参数的 1. 2. 5. 6 和 三个参数的 3. 4. 7. 接下来将对这个构造函数逐个分析学习.

1. public Handler()

public Handler() {
    this(null, false);
}
  • 解析:

内部调用的构造 6. 只不过第一个传入的的为 null, 第二个传入的为 false.

2. public Handler(Callback callback)

public Handler(Callback callback) {
    this(callback, false);
}
  • 解析:

内部调用的也是构造 6.第一个传入参数为callback 回调, 第二个依然为false, 回调 Callback会放在后面分析. 目前暂时先知道是一个回调就行了.

5. public Handler(boolean async)

public Handler(boolean async) {
    this(null, async);
}
  • 解析:

内部调用的也是构造 ⑥,第一个传入null,第二个参数为boolean类型的async


 
以上是一个无参和两个有参的, 1. 2. 5. 但是他们归根结底调用的都是构造函数 6. 所以现在一起看下构造函数 6.
 
6. public Handler(Callback callback, boolean async)

public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        //如果是匿名类, 内部类, 局部类,且没有声明 static,则存在内存泄露风险,所以打印日志进行提醒
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&(klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }
    //获得当前线程的 Looper
    mLooper = Looper.myLooper();
    //如果当前线程没有 Looper,则说明没有还没有调用 Looper.loop,抛异常
    if (mLooper == null) {
        throw new RuntimeException("Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()");
    }
    //把 Looper 的 Queue 赋值给 Handler 的 mQueue
    mQueue = mLooper.mQueue;
    //赋值给 callback
    mCallback = callback;
    //赋值  mAsynchronous
    mAsynchronous = async;
}
  • 解析:

使用当前线程的 Looper, 使用传入的回调, 并设置这个 Handler 是否是异步的.
除非在创建 Handler 的时候指定为异步的, 否则默认的 Handler 默认都是同步的.
异步消息相对于同步消息而言, 表示消息不会受到终端或者事件的影响其全局顺序, 异步消息是不会受到MessageQueue.enqueueSyncBarrier(long) 的同步障栅影响

Handler 默认采用的是当前线程 ThreadLocal 中的 Looper 对象, 只要执行了 Looper.prepare() 方法, 就可以获取有效的 Looper 对象. 同时在 消息机制的第三篇 Looper 篇 的时候也说了 Looper 的构造函数关联了 MessageQueueThread.
所以在同一个线程里面(已经调用了 Looper.prepare()), Handler中的 MessageQueueLooper中的 MessageQueue 指向的是同一个消息队列.

 
下面是三个参数的构造函数.
3. public Handler(Looper looper)

public Handler(Looper looper) {
  this(looper, null, false);
}
  • 解析

内部调用了构造 7. 传入参数不同.

4. public Handler(Looper looper, Callback callback)

public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}

不难发现, 上面两个默认调用的都是三个参数的构造函数, 都是非异步的.

7. public Handler(Looper looper, Callback callback, boolean async)

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}
  • 解析:

不使用默认的 Looper, 而使用由第一个参数传入的 Looper 对象.


 
综合 7 个构造函数, 可以发现其实构造函数的本质都是给下面四个本地变量赋值

  • mLooper
  • mQueue
  • mCallback
  • mAsynchronous

构造函数总结

  • 如果 Handler 的构造中没有给 Looper, 则使用默认的 Looper, 也就是在当前线程 ThreadLocal 中关联的 Looper.
    通过 ThreadLocal.Looper.mQueue 来给 Handler.mQueue 赋值.
    实现 Handler, Looper, MessageQueue 三者的绑定.
  • 通过构造函数来设置 Callback 的回调接口, 不设置则为 null.
  • 通过 mAsynchronous 来控制是同步还是异步, 而 mAsynchronous的默认值为 false. mAsynchronous 可以通过构造函数来设置.

 
最后来说一下回调接口, 也就是 Handler.Callback 接口

public interface Callback {
    public boolean handleMessage(Message msg);
}
  • 官方翻译:

通过设置这个接口去处理消息,就不需要再定义一个Handler的子类. 在调用 handler 构造函数的时候, 可直接使用这个接口. 返回值为 true 表示不继续向下分发, 返回 false 还会向下分发, 会调用 Handler.handleMessage() 方法. 在下一章 Handler 消息分发中会分析到.
(注意: 这个 handleMessage 可不是我们经常使用的那个. 这个是 callback 的 handleMessage.
我们经常使用的那个 handleMessageHandler 自带的一个方法. 也叫 handleMessage)

  • 理解

其实 Callback 可以和 Handelr.handleMessage 一起使用, 我尝试了一下, 可以产生类似过滤器的效果. 首先创建一个类继承自 Handler, 重写 void handleMessage 方法. 处理一些通用的消息. 然后在使用的 Activity 中, 创建 Handler 的时候, 使用我们自己定义的 Handelr, 其中参数传入 new Handler.Callback(), 并实现 boolean handleMessage . 在其中做一些处理. 示例如下.

class myHandler extends Handler{
    public myHandler(@Nullable Callback callback) {
        super(callback);
    }
    @Override
    public void handleMessage(@NonNull Message msg) {
        Log.e("myHandler","___what=" + msg.what);
        super.handleMessage(msg);
    }
}

public class MainActivity extends AppCompatActivity {

    Button button1,button2;
    private static  myHandler handler = new myHandler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            if(msg.what == 100){
                Log.e("myHandler","___Callback=" + msg.what);
                return true;
            }
            return  false;
        }
    });


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button1 = findViewById(R.id.button1);
        button2 = findViewById(R.id.button2);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message message = Message.obtain();
                message.what = 100;
                handler.sendMessage(message);
            }
        });
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message message = Message.obtain();
                message.what = 1000;
                handler.sendMessage(message);
            }
        });
    }
}
  • 点击 button1, 打印的是 ___Callback=100, 拦截了消息
  • 点击 button2, 打印的是 ___what=1000, 接收到了消息.

这是我对 Callback.handleMessage 的简单理解. 平时我们估计都不会经常用到这个 Callback, 估计一般用到的都是无参的 Handler.

本章对 Handler 的初识就到这里就结束了, 下一章会开始 Handler 对消息的发送进行分析和学习.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355