Android的消息机制—Handler机制

一、 基本概念

什么是消息机制? —— 不同线程之间的通信。
什么安卓的消息机制,就是 Handler 运行机制。
安卓的消息机制有什么用? —— 避免ANR(Application Not Responding) ,一旦发生ANR,程序就挂了,奔溃了。
什么时候会触发ANR?(消息机制在什么时候用?) —— 以下两个条件任意一个触发的的时候就会发生ANR
在activity中超过5秒的时间未能响应下一个事件
BroadcastReceive超过10未响应
造成以上两点的原因有很多,比如网络请求, 大文件的读取, 耗时的计算等都会引发ANR
如何避免ANR
首先明白两点:
主线程不能执行耗时操作(避免ANR)
子线程不能直接更新UI界面

可能有很多小伙伴想问为什么系统不允许子线程更新UI呢?
因为的UI控件不是线程安全的。
如果在多线程中并发访问可能会导致UI控件处于不可预期的状态,那为什么不对UI控件的访问加上 上锁机制 呢?因为有这么两个缺点:
上锁会让UI控件变得复杂和低效
上锁后会阻塞某些进程的执行

对于手机系统来说,这两个缺点是不可接受的,所以最简单高效的方法就是 —— 采用单线程模型来处理UI操作。
对开发者而言也不是很麻烦,只是通过Handler切换一下访问的线程的就好。
下面通过一个倒计时的小Demo来玩一下handler:
Handler的简单使用
既然子线程不能更改界面,那么我们现在就借助Handler让我们更改一下界面:
主要步骤是这样子的:
1、new出来一个Handler对象,复写handleMessage方法
2、在需要执行更新UI的地方 sendEmptyMessage 或者 sendMessage
3、在handleMessage里面的switch里面case不同的常量执行相关操作
package com.example.forget.handledemo;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {
    private Button btn;
    private static final int UPDATA = 0x123;
    //d定义一个handler对象,对其它线程发过来的消息进行处理
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATA:
                    btn.setText(msg.obj + "秒");
                    break;
            }
            super.handleMessage(msg);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn = (Button) findViewById(R.id.btn);
    }

    //新开一条线程更新UI控件
    public void ck(View view) {
        new Thread() {
            @Override
            public void run() {
                for (int i = 10; i >= 0; i--) {
//                    利用消息池产生消息对象
                    Message msg = Message.obtain();
                    msg.what = UPDATA;
                    msg.obj = i;
                    handler.sendMessage(msg);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                super.run();
            }
        }.start();

    }
}
效果图如下:

二、消息机制的简单分析(下一篇博客会进行分析源码)

(本文先简单介绍下)

三、Handler主要方法

Handler主要工作
主要工作:消息的 发送 和 接受 。
Handler消息发送的形式(post和send)
Post常用的方法如下:
final boolean  post(Runnable r) 发送一个runnable对象
final boolean  postAtTime(Runnable r, long uptimeMillis)  在特定的时间发送一个runnable 
final boolean  postDelayed(Runnable r, long delayMillis)  延迟特定的时间后发送runnable
Send常用的方法:
final boolean  sendEmptyMessage(int what) 
final boolean  sendEmptyMessageAtTime(int what, long uptimeMillis) 
final boolean  sendEmptyMessageDelayed(int what, long delayMillis) 
final boolean  sendMessage(Message msg) 
final boolean  sendMessageAtTime(Message msg, long uptimeMillis) 
final boolean  sendMessageDelayed(Message msg, long delayMillis)
两种形式,post和send
其实post最终还是会调用send
Handler的部分post和send的源码
post部分
我们发现,几个关于post的方法里面,调来调去就是3个方法
sendMessageDelayed
sendMessageAtTime
sendMessageAtFrontOfQueue (postAtFrontOfQueue方法一家独有)
public final boolean post(Runnable r)
{
       return  sendMessageDelayed(getPostMessage(r), 0);
}

public final boolean postAtTime(Runnable r, long uptimeMillis)
{
        return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}

public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}

public final boolean postDelayed(Runnable r, long delayMillis)
{
        return sendMessageDelayed(getPostMessage(r), delayMillis);
}


public final boolean postAtFrontOfQueue(Runnable r)
{
        return sendMessageAtFrontOfQueue(getPostMessage(r));
}
send部分
我们发现,send相关的方法也有5个,这5个方法调用的就是这么几个方法
sendMessageDelayed
sendMessageAtTime
sendEmptyMessageDelayed (sendEmptyMessage方法一家独占)
public final boolean sendMessage(Message msg)
{
        return sendMessageDelayed(msg, 0);
}

public final boolean sendEmptyMessage(int what)
{
        return sendEmptyMessageDelayed(what, 0);
}

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
}

public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
}


public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
我们看到,5个post方法,5个send方法,这10个方法加起来调来调去也就是另外的4个方法,分别是
sendMessageDelayed (post和send都有调用)
sendMessageAtTime (post和send都有调用)
sendMessageAtFrontOfQueue (postAtFrontOfQueue方法一家独有)
sendEmptyMessageDelayed (sendEmptyMessage方法一家独占)
我们发现,sendMessageAtTime和sendMessageAtFrontOfQueue这两个方法最终都是调用Handler里面的enqueueMessage方法
sendMessageDelayed调用了sendMessageAtTime,sendMessageAtTime最后也是调用enqueueMessage
最曲折的路线,sendEmptyMessageDelayed调用了sendMessageDelayed,然后sendMessageDelayed sendMessageAtTime,最后sendMessageAtTime调用enqueueMessage。
也就是说,除了post方式的postAtFrontOfQueue方法所调用的sendMessageAtFrontOfQueue方法不用postAtTime,
其他的post和send加起来的9个方法都直接或者间接地调用了
postAtTime 方法。
小结
最终,5个send的方法和5和post的方法,post和send加起来的9个方法都利用postAtTime进入了enqueueMessage方法,
剩下1个的独特的postAtFrontOfQueue方法利用sendMessageAtFrontOfQueue也进入了enqueueMessage方法
Handler的enqueueMessage方法调用了MessageQueue里面的enqueueMessage,enqueueMessage就是让Hadler通过post或者send发送过来的Message进入到MessageQueue的队列。
(好了,下一篇文章,我们通过源码来分析Handler机制)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值