转载请注明出处:http://blog.csdn.net/vnanyesheshou/article/details/72677227

深入理解Handler、Looper、Messagequeue

Android HandlerThread详解

最近看了一篇关于Handler的博客,感觉写的很不错,涉及了Handler的基本使用方法,及Handler、Looper、MessageQueue的深入分析。
原文地址:http://blog.csdn.net/zrf1335348191/article/details/50716983
虽然平常用Handler比较多,但是并没有深刻理解其内部原理,知其然而不知其所以然,为了知其所以然,还是应该好好研究下Handler的。先整理一篇Handler的基本使用。
Andorid是单线程模型的,当一个程序第一次启动时,Android会同时启动一个主线程(Main Thread),主线程主要负责处理与UI相关的事件。Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。
在开发中,我们经常会需要做一些耗时的操作:比如下载图片、打开网页、下载视频等。如果将这些耗时的操作放在主线程(UI线程),长时间的阻塞导致应用ANR。必然应该将这些操作放在子线程中处理,这些操作处理过程中,我们需要更新UI界面以告知用户现在具体的进度、状态等信息。
Handler提供了三种方式解决我们这个问题(在一个新线程中更新主线程中的UI控件),一种是调用sendMessage方法,一种是通过post方法,另一种是obtainMessage。


sendMessage

package cn.vn.hand;

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 implements OnClickListener {
private final String TAG = "MainActivity";
private TextView mTipTv;
private Button mDownloadBt;
private boolean isDownloading = false;
public final int MSG_DOWN_FAIL = 1;
public final int MSG_DOWN_SUCCESS = 2;
public final int MSG_DOWN_START = 3;
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch(msg.what){
case MSG_DOWN_FAIL:
mTipTv.setText("download fial");
break;
case MSG_DOWN_SUCCESS:
mTipTv.setText("download success");
break;
case MSG_DOWN_START:
mTipTv.setText("download start");
break;
}
};
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
} private void initView() {
mTipTv = (TextView) findViewById(R.id.tv_tip);
mDownloadBt = (Button) findViewById(R.id.bt_start);
mDownloadBt.setOnClickListener(this);
} @Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bt_start:
if(!isDownloading){
new MyThread().start();
}
break;
default:
break;
}
} class MyThread extends Thread {
@Override
public void run() {
isDownloading = true;
Log.d(TAG,"MyThread start run");
//发送消息给mHander
mHandler.sendEmptyMessage(MSG_DOWN_START);
try { //让线程睡眠3s。
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg = new Message();
msg.what = MSG_DOWN_SUCCESS;
//msg.arg1 = 111; 可以设置arg1、arg2、obj等参数,传递这些数据
//msg.arg2 = 222; msg.obj = obj;
mHandler.sendMessage(msg);
isDownloading = false;
Log.d(TAG,"MyThread stop run");
}
}
}

使用步骤:

  1. 在UI线程中创建handler对象mHandler,并实现handleMessage方法,根据Message的what值进行不同的处理操作。
  2. 创建Message对象
  3. 根据需要设置Message的参数,Message.what一般都是必要的,用来区分不同的Message,做出不同的操作。还可以设置Message两个int型字段arg1、arg2。当然除了这简单的数据外,还可以设置携带复杂数据,其obj字段类型为Object类型,可以为任意类类型的数据。也可以通过Message的setData方法设置Bundle类型的数据,可以通过getData方法获取该Bundle数据。
  4. mHandler.sendMessage(Message)方法将Message传入Handler中的消息队列中,然后handleMessage中对消息进行处理。

创建Handler的线程和其handleMessage运行的线程是同一线程,mHandler是在主线程中创建的,所以其handleMessage方法也是在主线程中运行。mHandler.sendMessage(Message)可以在主线程中也可以在子线程中,发送消息的线程与其执行的线程没有联系,最终都会在其创建的线程中处理这些消息。
sendMessage还有许多变形,可以发送空message(只携带what参数)、延时消息、定时消息等。使用方式很简单。

对于延时、定时消息,有时我们可能会想取消消息,这就可以通过removeMessages(int what)、或removeMessages(int what, Object object)、removeCallbacksAndMessages(Object token)将指定消息移除。

post

package cn.vn.hand;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends Activity implements OnClickListener {
private final String TAG = "MainActivity";
private TextView mTipTv;
private Button mDownloadBt;
private boolean isDownloading = false;
public final int MSG_DOWN_FAIL = 1;
public final int MSG_DOWN_SUCCESS = 2;
public final int MSG_DOWN_START = 3;
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
Log.d(TAG, "handlemessage what="+msg.what);
switch(msg.what){
case MSG_DOWN_FAIL:
mTipTv.setText("download fial");
break;
case MSG_DOWN_SUCCESS:
mTipTv.setText("download success");
break;
case MSG_DOWN_START:
mTipTv.setText("download start");
break;
}
};
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
} private void initView() {
mTipTv = (TextView) findViewById(R.id.tv_tip);
mDownloadBt = (Button) findViewById(R.id.bt_start);
mDownloadBt.setOnClickListener(this);
} @Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bt_start:
if(!isDownloading){
//new MyThread().start();
new postThread().start();
}
break;
default:
break;
}
} class postThread extends Thread{
@Override
public void run() {
isDownloading = true;
Log.d(TAG,"run threadid="+Thread.currentThread().getId()+
",name="+Thread.currentThread().getName());
try { //让线程睡眠3s。
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.post(new Runnable() {
@Override
public void run() {
Log.d(TAG, "Runnable threadid="+Thread.currentThread().getId()
+",name="+Thread.currentThread().getName());
//更新ui
mTipTv.setText("download success");
}
});
isDownloading = false;
}
}
}

Handler的post方法参数为Runnable对象,mHandler是在主线程中创建的,所以Runnalbe会在主线中运行(与Runnable创建的线程无关、与mHandler.post方法调用的线程无关)。

05-26 03:49:20.877: D/MainActivity(1297): run threadid=99,name=Thread-99
05-26 03:49:23.877: D/MainActivity(1297): Runnable threadid=1,name=main

有打印可确定Runnable的run方法确实是在主线程中运行的,可以更新UI。
post方法与sendMessage类似也有多个相似方法:

post延时、定时处理Runnable也可以进行取消,可以通过removeCallbacks(Runnable r)、removeCallbacks(Runnable r, Object token)、removeCallbacksAndMessages(Object token)方法进行取消。


obtainMessage

obtainMessage与sendmessage类似,也可以看成一种。

class obtainThread extends Thread{
@Override
public void run() {
isDownloading = true;
mHandler.obtainMessage(MSG_DOWN_START).sendToTarget();
try { //让线程睡眠3s。
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.obtainMessage(MSG_DOWN_SUCCESS).sendToTarget();
isDownloading = false;
}
}

mHandler.obtainMessage()生成Message对象,此对象携带其target对象,直接调用sendToTarget方法就可以将该消息发送到mHandler对应的消息队列中,然后在mHandler的handleMessage中进行处理。使用和sendMessage类型,都是发送Message对象。

这就差不多说完了,handler的一些基本使用方法,下篇分析下其原理。

Android 开发 Handler的基本使用的更多相关文章

  1. android 开发Handler源码剖析

    Android的消息机制主要是Handler的运行机制,而讲Handler的机制,又需要和MessageQueue和Looper结合.MessageQueue中文意思是消息队列,虽说叫队列,但是其内部 ...

  2. 【转】Android开发中Handler的使用

    在Android开发中,我们经常会遇到这样一种情况:在UI界面上进行某项操作后要执行一段很耗时的代码,比如我们在界面上点击了一个”下载“按钮,那么我们需要执行网络请求,这是一个耗时操作,因为不知道什么 ...

  3. Android开发手记(28) Handler和Looper

    Android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道.平 ...

  4. Android开发之使用Handler封装下载图片工具类(源码分享)

    假设每下载一张图片,就得重写一次Http协议,多线程的启动和handler的信息传递就显得太麻烦了,我们直接来封装一个工具类,便于我们以后在开发时随时能够调用. (1)在清单文件加入权限 <us ...

  5. Android开发之漫漫长途 ⅥI——Android消息机制(Looper Handler MessageQueue Message)

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  6. Android开发之漫漫长途 Ⅶ——Android消息机制(Looper Handler MessageQueue Message)

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  7. Android开发--多线程之Handler

    前言 Android的消息传递机制是另外一种形式的“事件处理”,这种机制主要是为了解决Android应用中多线程的问题,在Android中不 允许Activity新启动的线程访问该Activity里的 ...

  8. Android开发:图文分析 Handler通信机制 的工作原理

    前言 在Android开发的多线程应用场景中,Handler机制十分常用 下面,将图文详解 Handler机制 的工作原理 目录 1. 定义 一套 Android 消息传递机制 2. 作用 在多线程的 ...

  9. 【Android 开发】: Android 消息处理机制之一: Handler 与 Message

    最近几讲内容,我们学习了Android中关于多线程的一些知识,上一讲我们讲解了异步任务 AsyncTask 的操作,Android中还提供了其他的线程操作,如Handler Message Messa ...

随机推荐

  1. 在云服务器跑Python程序

    最近在鼓弄这TensorFlow的模型,有些模型实在是太大了,CPU占用率100%不说,还一跑起来就跑个大半天,严重影响了学习的进度,所以由于手里刚有一个不大使用的云服务器,配置虽然不咋地,至少还能跑 ...

  2. CSS学习笔记-05 过渡模块的基本用法

    话说 1对情侣两情相悦,你情我愿.时机成熟,夜深人静...咳 ,如果就这么直奔主题,是不是有点猴急,所以,还是要来点前戏@. 铛 铛, 这个时候 过渡模块出现了. 划重点: 上代码: <!DOC ...

  3. ubuntu 安装 nvm 管理Node.js 以及vim 插件增强

    安装curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bashsource ~/.bashr ...

  4. raid的一些简单知识

    日一.RAID定义RAID(Redundant Array of Independent Disk 独立冗余磁盘阵列)技术是加州大学伯克利分校1987年提出,最初是为了组合小的廉价磁盘来代替大的昂贵磁 ...

  5. oracle 汉字转拼音

    oracle汉字转拼音(获得全拼/拼音首字母/拼音截取等) 效果如下: Oracle 字符集 GBK 没有问题 , UTF -8 需要修改一下 Sql代码 --oracle汉字转拼音 PACKAGE ...

  6. [Spring Boot]什么是Spring Boot

    <Spring Boot是什么> Spring Boot不是一个框架 是一种用来轻松创建具有最小或零配置的独立应用程序的方式 用来开发基于Spring的应用,但只需非常少的配置. 它提供了 ...

  7. JDBC ---获取数据字段 -- 转成map

    getConn = JdbcDataBaseUtil.getConnection(user,pwd,serverUrl,mysqDriver); //建立一个结果集,用来保存查询出来的结果 Resul ...

  8. layui选项卡-内容为echarts图显示不全的问题

    var width = $("威胁类型ID").width();var height = $("威胁类型ID").height(); $("#威胁来源 ...

  9. [c#]_ELVE_Message多功能用法

     1.   当要显示如图3个按钮时,并要获得单击不同按钮的进行不同的相应时,可以在MessageBoxButtons后面添加一个.(应该英文的点,此处为了醒目,用中文代替)可以看到提示框下方需要几个按 ...

  10. PythonStudy——文件操作 File operation

    # 文件:就是硬盘的一块存储空间 # 1.使用文件的三步骤: # 打开文件- 得到文件对象:找到数据存放在硬盘的位置,让操作系统持有该空间,具有操作权# 硬盘空间 被 操作系统持有# 文件对象f 被 ...