Handler消息传递机制
引言:
出于性能优化考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,可能导致线程安全问题。
为了解决这个问题,Android制定了一条简单的规则:只允许UI线程修改Acitivity里的组件,这样就会导致新启动的线程无法动态改变组建的属性值。
但在实际的应用开发中,需要让新启动的线程改变界面组件的属性值,这就需要借助与Handler的消息传递机制来实现了。
一、Handler的使用
Handler类的主要作用有两个:
》在新启动的线程中发送消息
》在主线程中获取,处理消息
为了让主线程能“适时”的处理新启动的线程发送的消息,只能通过回调的方式来实现。
重写Handler类中处理消息的方法;新启动的线程发送消息时消息会发送到与之关联的MessageQueue;而Handler会不断地从MessageQueue种获取并处理消息;这将导致handler类中处理消息的方法被回调。
new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } Message msg = handler.obtainMessage(); msg.what = Constant.USER_LOGIN; msg.obj = "您尚未注册,是否快捷登录"; handler.sendMessage(msg); } }).start();
Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { super.handleMessage(msg); if (activity.isFinishing()) { return; } if (msg.what == Constant.USER_LOGIN) { ToastUtils.showShort(activity, msg.obj.toString()); } } };
二、与Handler一起工作的几个组件,Looper、MessageQueue
》Looper:每个线程只有一个Looper,负责管理MessagQueue,会不断地总MessageQueue中取出消息,并将消息分给对应的Handler处理。
》MessageQueue:由Looper负责管理。采用先进先出的方式来管理Message。
》Handler:把消息发送给Looper管理的MessageQueue,并负责处理Looper分给它的消息。
三、使用Handler源码分析:
在线程中使用Handler的步骤如下。
private class LooperThread extends Thread { public Handler mHandler; @Override public void run() { Looper.prepare(); mHandler = new Handler() { @Override public void handleMessage(Message msg) { Log.i(TAG, msg.toString()); } }; Looper.loop(); } }
-调用Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,构造器会创建与之配套的MessageQueue。
public final class Looper { private static final String TAG = "Looper"; // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static Looper sMainLooper; // guarded by Looper.class final MessageQueue mQueue; final Thread mThread; private Printer mLogging; }
public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //这里new一个Looper对象 sThreadLocal.set(new Looper(quitAllowed)); } }
-有了Looper之后,创建Handler子类的实例,重写handleMessage()方法,该方法负责处理来自于其他线程的消息。
//构造方法 public Handler() {this(null, false);} public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); 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()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
-调用Looper的loop()方法启动Looper。
public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); //获取消息队列的笑一个消息,没有消息将会阻塞 if (msg == null) { // 如果消息为空,表明消息队列正在退出 return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } msg.target.dispatchMessage(msg); if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // 使用final修饰标识符,保证在分发消息的过程中线程标识符不会被更改 final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycle(); } }
Handler消息传递机制的更多相关文章
- 安卓开发_深入理解Handler消息传递机制
一.概述 因为子线程的run()方法无法修改UI线程(主线程)的UI界面,所以Android引入了Handler消息传递机制,实现在新创建的线程中操作UI界面 二.消息类(Message) 消息类是存 ...
- Android学习笔记-事件处理之Handler消息传递机制
内容摘要:Android Handler消息传递机制的学习总结.问题记录 Handler消息传递机制的目的: 1.实现线程间通信(如:Android平台只允许主线程(UI线程)修改Activity里的 ...
- 事件处理机制与Handler消息传递机制
一.基于监听的事件处理机制 基于监听的时间处理机制模型: 事件监听机制中由事件源,事件,事件监听器三类对象组成 处理流程如下: Step 1:为某个事件源(组件)设置一个监听器,用于监听用户操作 St ...
- Android学习之Handler消息传递机制
Android只允许UI线程修改Activity里的UI组件.当Android程序第一次启动时,Android会同时启动一条主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户 ...
- Handler消息传递机制——Handler类简洁
Handler类的主要作用有两个: 在新启动的线程中发送消息. 在主线程中获取.处理消息. 上面的说法很简单,只要分成两步即可:在新启动的线程中发送消息:然后在主线程上获取.并处理消息.但这个过程涉及 ...
- Android Handler消息传递机制
在Android系统中,类Handler主要有如下两个作用. 在新启动的线程中发送消息. 在主线程中获取.处理消息. 类Handler在实现上述作用时,首先在新启动的线程中发送消息,然后在主线程中获取 ...
- Handler 消息传递机制
1,Handler 的概念Handler 是用来干什么的?1)执行计划任务,可以在预定的时间执行某些任务,可以模拟定时器 2)线程间通信.在Android的应用启动时,会创建一个主线程,主线程会创建一 ...
- Android中的消息机制:Handler消息传递机制
参考<疯狂android讲义>第2版3.5 P214 一.背景 出于性能优化考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,可能导致线程安全问题.为 ...
- Handler消息传递机制——Handler、Loop、MessageQueue的工作原理
为了更好地理解Handler的工作原理,先介绍一下与Handler一起工作的几个组件. Message:Handler接收和处理的消息对象. Looper:每个线程只能拥有一个Looper.它的loo ...
随机推荐
- hdu 4023 2011上海赛区网络赛C 贪心+模拟
以为是贪心,结果不是,2333 贪心最后对自己绝对有利的情况 点我 #include<cstdio> #include<iostream> #include<algori ...
- excel、csv、txt文件数据读取
/// <summary> /// 读取Excel表每一行第一列的字符串集合 /// </summary> /// <param name="filePath& ...
- Mac OS 您需要安装旧 Java SE 6 运行环境才能打开“XXX” 问题
问题描述: 今天在Mac OS上安装一个app的时候提示 “您需要安装旧 Java SE 6 运行环境才能打开 XXX” ,在网上搜索了一下,有说要改app的info.plist文件的,将其中的JVM ...
- LR连接oracle时出现:SQLState=28000[Oracle][ODBC][Ora]ORA-01017:invalid username/password;logon denied
出现的现象:
- 使用JdbcTemplate报 Incorrect column count: expected 1, actual 5错误解决
Incorrect column count: expected 1, actual 5 在使用jdbc的querForObject queryForList的时候,出现Incorrect colum ...
- Android的ADB配置环境和adb指令使用
adb的全称为Android Debug Bridge,就是起到调试桥的作用,作为一名开发者倒是常用到这个工具.借助adb工具,我们可以管理设备或手机模拟器的状态.还可以进行很多手机操作,如安装软件. ...
- jquery的siblings()
jquery 点击 感兴趣 感兴趣变为 蓝色 去掉onclick事件 不感兴趣 变为 黑色 加上点击事件 点击 不感兴趣 不感兴趣变为 蓝色 去掉onclick 感兴趣 变为 黑色 加上点击事件 ht ...
- 当 NSDictionary 遇见 nil
Demo project: NSDictionary-NilSafe 问题 相信用 Objective-C 开发 iOS 应用的人对下面的 crash 不会陌生: *** -[__NSPlacehol ...
- 疯狂java学习笔记之面向对象(五) - 封装、继承、多态
一.封装: 封装的概念: - 合理的隐藏:隐藏不想被外界操作的Field.方法.构造器 - 合理的暴露:一般就是希望给别人调用的方法 e.g:显示器(按键暴露出来操作,但实际的东西/细节方法被隐藏起来 ...
- HD1394 Minimum Inversion Number
这道题目的意思是:给你一个序列,统计一开始的逆序数的个数,然后依次把第一个元素放到序列末尾,求每次的逆序数个数,求出每次求逆序数里,逆序数最小的那个数 这里需要推一个递推式,就是每次你把第一个元素放到 ...