android Handler及消息处理机制的简单介绍
学习android线程时,直接在UI线程中使用子线程来更新TextView显示的内容,会有如下错误:android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
大致意思就是:只有创建这个控件的线程才能去更新该控件的内容。
android中,如果要操作UI,都必须在UI线程,即主线程中去做,我们不能直接在UI线程中去创建子线程来实现,即不能通过这种方式来实现:
new Thread( new Runnable() { public void run() { textView.setText("update"); } }).start();
要想实现更新TextView显示的内容,要利用消息机制:Handler;
消息机制的三个方面,也可以是四个方面:
(1)Looper:一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列);
(2)Handler:使用Handler发送消息对象到消息队列,或者接受Looper从消息队列里取出来的消息;
(3)MessageQueue:用来存放线程放入的消息;
(4)线程:UI Thread通常就是main Thread,而Android启动程序时会替它建立一个MessageQueue;
1.Handler创建消息:
每一个消息都需要被指定的Handler处理,通过Handler创建消息便可完成此功能。
Android消息机制中引入了消息池,Handler创建消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。
使用消息池的好处是:消息不被使用时,并不作为垃圾回收,而是放入消息池,可供下次Handler创建消息时使用,消息池提高了消息对象的复用,减少系统垃圾回收的次数。
消息的创建流程如图所示:
2.Handler发送消息
UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应,使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper,这点可以查看android的源代码;
之后其他Handler初始化的时候直接获取第一个Handler创建的Looper,而Looper初始化的时候会创建一个消息队列MessageQueue。
至此,主线程、消息循环、消息队列之间的关系是1:1:1;
Handler、Looper、MessageQueue的初始化流程如图所示
而Hander持有对UI主线程消息队列MessageQueue和消息循环Looper的引用,子线程可以通过Handler将消息发送到UI线程的消息队列MessageQueue中;
3.Handler处理消息
UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出;
首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。
子线程通过Handler、Looper与UI主线程通信的流程如图所示:
下面我们用一个例子来实现更新UI Thread中TextView的内容;
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.xiaozhang.handler1.MainActivity" > <TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="@string/hello_world" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/textView" android:text="button" /> </RelativeLayout>
MainActivity.java
package com.xiaozhang.handler1; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { private Button button; private TextView textView; private Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.button); textView = (TextView) findViewById(R.id.textView); button.setOnClickListener(new ButtonListener()); handler = new MyHandler(); } class MyHandler extends Handler { @Override public void handleMessage(Message msg) { textView.setText((String) msg.obj); } } class ButtonListener implements OnClickListener { @Override public void onClick(View v) { Thread t = new MyThread(); t.start(); } } class MyThread extends Thread { @Override public void run() { try { Thread.sleep(2 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } String s = "the message from child thread!"; Message msg = handler.obtainMessage(); msg.obj = s; handler.sendMessage(msg); } } }
注:MainActivity中的内部类一般通过匿名内部类来实现;
例如:
package com.xiaozhang.handler1; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { private Button button; private TextView textView; private Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.button); textView = (TextView) findViewById(R.id.textView); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { new Thread() { @Override public void run() { try { Thread.sleep(2 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } String s = "the message from child thread!"; Message msg = handler.obtainMessage(); msg.obj = s; handler.sendMessage(msg); } }.start(); } }); handler = new Handler() { @Override public void handleMessage(Message msg) { textView.setText((String) msg.obj); } }; } }
我只是随便写了下,应该还可以再进行改进;
显示效果为:
然后点击button,等待2秒后,再次显示为:
文章参考及整理自:
http://blog.csdn.net/itachi85/article/details/8035333
Mars视频;
推荐:
http://www.jb51.net/article/33514.htm
android Handler及消息处理机制的简单介绍的更多相关文章
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类(转)
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38476887 ,本文出自[张鸿洋的博客] 最近创建了一个群,方便大家交流,群号: ...
- Android Handler 异步消息处理机制的妙用 创建强大的图片载入类
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38476887 ,本文出自[张鸿洋的博客] 近期创建了一个群.方便大家交流,群号: ...
- Android中Handler的消息处理机制以及源码分析
在实际项目当中,一个很常见的需求场景就是在根据子线程当中的数据去更新ui.我们知道,android中ui是单线程模型的,就是只能在UI线程(也称为主线程)中更新ui.而一些耗时操作,比如数据库,网络请 ...
- 从Handler+Message+Looper源代码带你分析Android系统的消息处理机制
PS一句:不得不说CSDN同步做的非常烂.还得我花了近1个小时恢复这篇博客. 引言 [转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 作为A ...
- 使用Kotlin开发Android应用(I):简单介绍
使用Kotlin开发Android应用(I):简单介绍 @author ASCE1885的 Github 简书 微博 CSDN 原文链接 Kotlin是一门基于JVM的编程语言.它正成长为Androi ...
- Android应用程序消息处理机制(Looper、Handler)分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6817933 Android应用程序是通过消息来 ...
- Android多线程----异步消息处理机制之Handler详解
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...
- Android应用程序消息处理机制笔记
看老罗的Android源码情景分析学习的时候,边抄边理解再总结.希望能为面试提供点帮助吧. 1.Android应用程序是通过消息来驱动,Android应用程序每一个线程在启动时,都可以首先在内部创建一 ...
- [Android]Handler的消息机制
最经面试中,技术面试中有一个是Handler的消息机制,细细想想,我经常用到的Handler无非是在主线程(或者说Activity)新建一个Handler对象,另外一个Thread是异步加载数据,同时 ...
随机推荐
- 我为什么要再给lua写一个json模块
最近要给自己编写的服务器加上json解析模块.根据我当前的项目,可以预测服务器中使用json的地方: 通信.由于与客户端通信使用google protocolbuffer,仅在与SDK通信中使用jso ...
- sublime3 使用技巧
Ctrl+O(Command+O)可以实现头文件和源文件之间的快速切换 Ctrl+Shift+T可以打开之前关闭的tab页,这点同chrome是一样的 Ctrl+R定位函数:Ctrl+G定位到行: 插 ...
- Swift补基础之Selector、条件编译、编译标记、NSObject
在swift中使用条件编译比较直接 #if <condition> #elseif <condition> #else #endif 例如 :在debug模式和release模 ...
- HDU4612(Warm up)2013多校2-图的边双连通问题(Tarjan算法+树形DP)
/** 题目大意: 给你一个无向连通图,问加上一条边后得到的图的最少的割边数; 算法思想: 图的边双连通Tarjan算法+树形DP; 即通过Tarjan算法对边双连通缩图,构成一棵树,然后用树形DP求 ...
- rpm包安装
RPM全称是“RedHatPackageManager”是由RedHat公司发发展起来的,本质是将软件源码包经过编译并且打包成rpm的格式,rpm文件包含的有二进制文件,配置文件,库文件等,同时RPM ...
- wpf-DataTemplate应用
在WPF中,决定数据外观的是DataTemplate,即DataTemplate是数据内容的表现形式,一条数据显示成什么样子,是简单的文本还是直观的图形,就是由DataTemplate决定的.下面通过 ...
- (转)巧用clear:both
我们在制作网页中用div+css或者称xhtml+css都会遇到一些很诡异的情况,明明布局正确,但是整个画面却混乱起来了,有时候在IE6下看的很正常的,到ie7或者火狐下看时,就一片混乱了,无论怎么计 ...
- Android material design support library -- CollapsingToolbarLayout简介
本文是codetrick上material design support library教程的第三篇,主要讲的是CollapsingToolbarLayout的概念和应用方法. 原文链接:Materi ...
- Segment,Path,Ring和Polyline的区别
这四者当中Segment是最小的单位,具体的构成路线可以分为两个条:Segment-Path-Ring(封闭的Path)Segment-Path-Polyline Segment 和 Path 可以说 ...
- java泛型中? super T和? extends T的区别
<? super T>表示包括T在内的任何T的父类,<? extends T>表示包括T在内的任何T的子类;请记住PECS原则:生产者(Producer)使用extends,消 ...