• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Android > Android消息机制

Android消息机制

作者:网友 字体:[增加 减小] 来源:互联网 时间:2017-05-26

网友通过本文主要向大家介绍了android消息推送机制,android消息处理机制,android消息传递机制,android消息发送机制,android handler机制等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Android消息机制


每一个Android应用在启动的时候都会创建一个线程,这个线程被称为主线程或者UI线程,Android应用的所有操作默认都会运行在这个线程中。

但是当我们想要进行数据请求,图片下载,或者其他耗时操作时,是不可能在这个UI线程做的,因为Android在3.0以后的版本已经禁止了这件事情,直接抛出一个异常。所以我们需要一个子线程来处理那些除UI操作的事情。
但是这个又会有一个问题,我们只能在UI线程进程UI操作,只能在子线程进行耗时操作,如果我们需要在耗时操作结束后在Android界面上显示一个View,我们应该怎么做?我们是不可能在子线程直接刷新UI的。这时我们需要用到Android的消息机制,来实现主线程和子线程的通信。简单来说,就是子线程获取到数据之后,不直接进行UI更新,而是把数据装到消息中发送到主线程,主线程中有一个循环轮询会立即收到子线程发过来的信息,然后拿到消息数据后在主线程更新UI。说起来比较简单,我们来仔细的看一下具体是怎么说的。

处理消息的手段——Handler, Looper, MessageQueue

Handler

我们先讲解一下Handler,Handler顾名思义就是处理者,通常对他的用法是在UI线程中新建一个Handler,并覆写他的handleMessage, 然后再耗时的线程中将消息post给UI线程,例子如下:

class MyHandler extends Handler{
    @Override
    public void handleMessage(Message msg){
    //更新UI
    }
}

MyHandler mHandler = new MyHandler();
new Thread(){
    public void run(){
        mHandler.sendEmptyMessage(123);
    };
}.start();

这里规定了Handler必须在主线程创建,因为只有在UI线程创建才会让Handler关联到已有的MessageQueue。而MessageQueue被封装到Looper中,而Looper又通过ThreadLocal封装到一个线程中,最后相当于MessageQueue关联了一个线程。所以简单来说就是Handler将消息投递到一个关联了线程的MessageQueue中,然后Handler在从MessageQueue中取出消息,并且处理它。
我们看一下Handler的2个常用的方法

void handleMessage(Message msg) :处理消息的方法
final boolean sendMessage(Message msg) :立即发送消息

第一个方法 我们通常在UI线程中执行,一般用来刷新UI,至于如果创建了一个非静态内部类产生对内存泄漏,建议参考这篇博客Handler引发的内存泄漏.第二个方法我们通常在子线程中执行,需要一个Handler的实例化对象,通常是由主线程去去传递给子线程。并且需要一个Message对象,指定他的msg.what作为消息的标示,但是如果我们只是用Handler去处理一个消息的时候,选择post方法是个更好的选择,例子如下:

private Handler mHandler = new Handler();

new Thread(new Runnable() {
    @Override
    public void run() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                //UI操作
                ...
            }
        });
    }
}).start();

下面我们接着讨论下消息的循环队列MessageQueue与包装他的Looper循环

Looper和MessageQueue

上面提到了在UI线程中创建并实例化Handler对象不需要Looper和MessageQueue,因为我们的应用在启动的时候先执行了ActivityThreadMain,在这个方法就是Java语言运行的入口public static void main(String [] args)在这里面创建了一个MainLooper,创建的过程如下:

public static void main(string[] args){
    //初始化
    Looper.prepareMainLooper();
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    if(sMainThreadHandler == null){
        sMainThreadHandler = thread.getHandler();
    }
    AsyncTask.init();
    //动起来
    Looper.loop();
}

这里面并没有MessageQueue的出现,我们可以看一看Looper类的源码,来了解在初始化的时候发生了什么有趣的事情。

public class Looper {
    private static final ThreadLocal sThreadLocal = new ThreadLocal();
    // Looper内的消息队列
    final MessageQueue mQueue;
    // 当前线程
    Thread mThread;
    // 。。。其他属性
    // 每个Looper对象中有它的消息队列,和它所属的线程
    private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }
    // 我们调用该方法会在调用线程的TLS中创建Looper对象
    public static final void prepare() {
        if (sThreadLocal.get() != null) {
            // 试图在有Looper的线程中再次创建Looper将抛出异常
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }
    // 其他方法
}

我们一行行的看这段代码,首先是实例化一个ThreadLocal对象,这个用来实现Looper循环的本地化存储,关于ThreadLocal可以看这篇文章为什么用ThreadLocal,简而言之就是当多个线程同时访问Looper对象的时候,我们不用synchronized同步机制来处理他,而是为每个线程创建一个自己的Looper副本,A线程改变了A的looper副本,不影响B线程的Looper,从而比较高效的实现线程安全。后面几句依次定义了MessageQueue,并对Looper进行了私有化构造,在prepare方法中将Looper对象设置给了sThreadLocal这样MessageQueue包装在了Looper对象中,同时通过ThreadLocal使得线程和Looper关联上,从而消息队列与线程关联上,并且不同的线程就不能访问对方的消息队列。
如下图所示:
Looper,MessageQueue,Thread三者示意图

接着就是Looper.loop循环执行起来,我们看一下,在loop方法里面执行了发生了什么事情

public static final void loop() {
        Looper me = myLooper();  //得到当前线程Looper
        MessageQueue queue = me.mQueue;  //得到当前looper的MQ
        
        while (true) {
            Message msg = queue.next(); // 取出message
            if (msg != null) {
                if (msg.target == null) {
                     return;
                }
              
                msg.target.dispatchMessage(msg);
               
                msg.recycle();
            }
        }
    }

这是省略版的代码,我们从这里看出无限循环执行,首先从消息队列中不断取出消息,然后不断msg是否为空,msg.target是否为空,不空的话,执行dispatchMessage方法,这个方法是handler的一个方法,由此我们可以看出msg.target是handler的类型,至此,通过Looper.prepare和Loop.loop实现了MessageQueue,Looper,Handler三者之间的关联。而Handler与Looper,和MessageQueue关联则是在Handler的默认构造器中,通过Looper.getLooper获取loop对象,从而获取MessageQueue,其源码如下:

public Handler(){
    //直接把关联looper的MQ作为自己的MQ,因此它的消息将发送到关联looper的MQ上
    mLooper = Looper.myLooper();
    mQueue = mLooper.mQueue;
    mCallback = null;
}

然后我们的流程图可以多些内容,如下所示:
Handler工作流程

我们接下来看一下dispatchMessage()方法,在该方法中实际上只是一个分发方法,如果Runable类型的callback为空,则执行handlerMessage来处理消息,该方法为空,需要覆写。如果不为空,则执行handleCallback。实际上,如果我们用handle的post方法,则就执行了callback,如果用sendMessage,则就执行了handleMessage

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Android的消息机制,Android消息机制
  • Android 几种消息推送方案总结,android方案
  • Android消息机制
  • android的消息机制
  • Android中接收系统广播消息

相关文章

  • 2017-05-26Android 查看自己的keystore的别名及相关信息,androidkeystore
  • 2017-05-26Android-将RGB彩色图转换为灰度图,
  • 2017-05-26Android自定义控件系列案例【四】
  • 2017-05-26JSON解析,json在线解析
  • 2017-05-26Activity生命周期,activity生命周期图
  • 2017-05-26我的android学习经历16,android学习经历16
  • 2017-05-26Android--字符串和16进制相互转化(解决中文乱码),android--进制
  • 2017-05-26关于linux的busybox工具mdev的使用和声卡热插拔以及驱动挂载的总结
  • 2017-05-26Android编程思想双11口诀,android编程思想
  • 2017-05-26Android 中的mvvm,Androidmvvm

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • Android5.0开发范例大全 读书笔记(三),android5.0范例
    • Android深入四大组件(五)ContentProvider的启动过程
    • android 完全解析模拟遥控器按键,android遥控器
    • 我的Android第二课,Android
    • 高仿人人网客户端Android版项目源码,高仿android
    • 静态库和动态库的生成和加载详解
    • AppManager,androidappmanager
    • 安卓第十六天笔记-音频与视频播放,安卓第视频播放
    • 深入理解Activity启动流程
    • 充值,充值平台

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有