Handler Android应用开发消息机制
来源:互联网 发布:odysseus windows 编辑:程序博客网 时间:2024/05/17 04:03
一、背景
当应用程序启动时,Android首先会开启一个主线程(即UI线程),主线程为管理界面中的UI控件、进行事件分发,比如:你要点击一个Button,Android会分发事件到Button上来响应你的操作。如果此时需要一个耗时操作,例如:联网读取数据或读取本地一个较大文本时,你不能把这些操作放在主线程中。如果你放在主线程中,界面会出现假死现象,如果5s后还没有完成的话则会收到Android系统的一个错误提示“强制关闭”。此时,我们则要把这些耗时的操作放在一个子线程中,因此此子线程涉及到了UI更新,而更新UI只能在主线程中更新,这时我们就需要引入Handler来实现该操作。它与子线程可以通过Message对象来传递消息,这个时候Handler就承担着接受子线程传过来的(子线程用sendMessage()方法传递)的Message对象(里面包含数据且该消息对象会放在主线程的消息队列MQ中),然后在主线程中处理这些消息从而可以对UI控件进行更新等操作。
二、Android的消息处理有三个核心类:Looper、Handler和Message
1、Looper
Looper使一个普通的线程变成Looper线程。Looper线程就是循环工作的线程,创建looper线程代码如下:
public class MyLoopThread extends Thread {@Overridepublic void run() {Looper.prepare(); //将当前线程初始化为Looper线程,实例Looper,初始化消息队列MessageQueue//.....其他处理,如实例化Handler等Looper.loop(); //循环从消息队列MessageQueue取消息分发给Handler处理}}
效果图如下:
注:一个线程(Thread)最多有且只能有一个Looper对象,该Looper对象内部包含了一个消息队列MessageQueue
由上面代码可以知道Looper对象的prepare()方法将会初始化当前线程为looper线程,并且实例化Looper和初始化消息队列;
而Looper的loop()方法则是循环取消息,并分发到对应的hangdler处理消息,原理如下图:
Looper类除了prepare()和loop()方法外,还有其他的方法,如下:
Looper.myLooper() :得到当前线程的Looper对象;
getThread() :得到Looper对象所属的线程
quit() :结束looper循环
2、Handler消息处理(异步处理处理)
主要接受子线程发送的消息,并用此数据配合主线程更新UI
解释:Handler扮演了往MQ上添加消息和处理消息(只处理自己发出的消息)的角色,即:通知MQ要要执行一个任务(sendMessage),并在looper.loop()方法关联到此Handler时执行任务(handlerMessage())然后Handler处理消息,整个过程是异步执行的。
注:因为Handler创建时会关联一个looper,默认的构造方法将关联到当前线程的looper,所以上面说的:“looper.loop()方法关联到此Handler”可以理解为handler创建时关联的looper是执行looper.loop()方法的looper线程的looper。所以,Handler关联的looper是可以设置的,可以为子looper线程的looper也可以是主线程(UI线程——也是一个looper线程)的looper,Handler关联的looper是哪个线程的looper它就会在那个线程执行(即:Handler的执行线程只与它关联的looper有关,与它实例化的位置无关)。Handler的实例化代码如下:
public class MyAndroidStudyMainActivity extends Activity {private Handler mHandler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_my_android_study_main);mHandler = new Handler(getMainLooper(), new Callback() {//实例化Handler并关联主线程的looper,当new Callback()//前面没有参数时实例化的Handler关联的则是当前所处线程的looper@Overridepublic boolean handleMessage(Message msg) {//.......处理消息(耗时操作)return true;}});}}将Handler加入到looperThread线程类中时,则可以异步处理消息了(如:在子线程中实例化Handler时关联UI线程的looper,我们在子线程中联网取数据后把数据发送给Handler,然后Handler处理消息就可以更新UI界面了)。结构代码如下:
public class MyLoopThread extends Thread {private Handler mHandler1;private Handler mHandler2;@Overridepublic void run() {Looper.prepare(); //将当前线程初始化为Looper线程,实例Looper,初始化消息队列MessageQueue//实例化两个HandlermHandler1 = new Handler();mHandler2 = new Handler();Looper.loop(); //循环从消息队列MessageQueue取消息分发给Handler处理}}效果图如下:
public class MyLoopThread extends Thread {private Handler mHandler1;@Overridepublic void run() {Looper.prepare(); //将当前线程初始化为Looper线程,实例Looper,初始化消息队列MessageQueue//实例化HandlermHandler1 = new Handler(getMainLooper(),new Callback() {@Overridepublic boolean handleMessage(Message msg) {//......更新UI界面return true;}});Looper.loop(); //循环从消息队列MessageQueue取消息分发给Handler处理}}【例】如下图所示,要在子线程中把界面上TextView控件的内容修改
XML文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_blue_dark" android:gravity="center" android:orientation="vertical" > <TextView android:id="@+id/message_txt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="我是启动界面" android:textColor="@android:color/white" android:textSize="24sp" /> <Button android:id="@+id/send_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="发送消息到主线程执行" /></LinearLayout>
Java代码:
public class HandlerActivity extends Activity {private MyLoopThread myLooper;//定义子线程private TextView mMessageTxt;//定义TextViewprivate Button mSendMsgBtn;//定义Buttonprivate int count = 1; // 标识消息@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);//隐藏标题setContentView(R.layout.activity_handler_layout);mMessageTxt = (TextView) findViewById(R.id.message_txt);mSendMsgBtn = (Button) findViewById(R.id.send_btn);myLooper = new MyLoopThread();//实例子线程myLooper.start();//启动子线程mSendMsgBtn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Message msg = Message.obtain();msg.what = 11;msg.arg1 = count++;myLooper.mHandler1.sendMessage(msg);//Handler发送消息}});}/** * 消息在主线程执行的情况 消息在子线程执行的情况 * */public class MyLoopThread extends Thread {public Handler mHandler1;@Overridepublic void run() {Looper.prepare(); //实例Looper,初始化消息队列MessageQueuemHandler1 = new Handler(getMainLooper(), new Callback() {@Overridepublic boolean handleMessage(Message msg) {//Handler处理消息,更新UIint arg1 = msg.arg1;mMessageTxt.setText("主线程执行 : 消息 " + arg1);return true;}});Looper.loop(); //循环从消息队列MessageQueue取消息分发给Handler处理}}}运行程序后如下图:
- Handler Android应用开发消息机制
- Android 开发中的消息机制 Handler 机制
- Android 开发中的消息机制 Handler 机制
- Android开发之Handler消息传递机制
- Android开发Handler消息机制深入探究
- Android开发之Handler消息机制
- Android Handler消息机制
- android handler消息机制
- android handler消息机制
- Android Handler消息机制
- android handler消息机制
- android handler消息机制
- Android:Handler消息机制
- Android Handler 消息机制
- Android Handler消息机制
- android消息机制handler
- Android 消息机制--handler
- android消息机制-handler
- hdu1847 Good Luck in CET-4 Everybody!
- 精益之美甚于帕斯雀(摘自《代码之道》第2章)
- 自学QT之简易音乐播放器基于QT5.5
- OpenCV-Mat结构详解
- 传输层
- Handler Android应用开发消息机制
- 【IOS 开发学习总结-OC-62】IOS 应用的生命周期
- 开始记录 iOS后台计时的代码。
- 线段树模板
- 重构:运用Java反射加多态 “干掉” switch
- 斯坦福大学公开课 iOS应用开发教程学习笔记(第六课)多个MVC的程序和故事版、UINavigationController、 Segues
- 学生信息是:姓名,学号,性别,年龄,用一个链表,把这些信息连在一起,给出一个age, 在些链表中删除学生年龄等于age的学生信息。
- 软件自动化测试工具介绍
- UIButton详解