android消息传递工作机制,Android 的消息机制(Handler消息传递机制)

出于性能优化考虑,android的UI操作并不是线程安全的,这意味着意味着如果有多个线程并发操作UI组件,可能导致线程安全问题,未解决此问题,

从开发的角度来说, Handler 是 Android 消息机制的上层接口, 这使得在开发过程中只需要和 Handler 交互即可。

Handler 的使用过程很简单,通过它可以轻松地将一个任务切换到 Handler 所在的线程中去执行。很多人认为

Handler的作用是更新 UI, 这的确没错,但是更新 UI 仅仅是 Handler 的一个特殊的使用场景.具体来说是这样的:

有时候需要在子线程中进行耗时的 I/O 操作,可能是读取文件或者访问网络等, 当耗时操作完成以后可能需要在 UI 上做一些改变, 由于

Android 开发规范的限制,我们并不能在子线程中访问 UI 控件,否则就会触发程序异常, 这个时候通过Handler 就可 以将更新

UI 的操作切换到主线程中执行。 因此,本质上来说, Handler 并是专门用于更新 UI 的,它只是常被开发者用来更新 UI。

Android 的消息机制主要是指 Handler 的运行机制, Handler 的运行需要底层的MessageQueue 和

Looper 的支撑。 MessageQueue 的中文翻译是消息队列,顾名思义,

它的内部存储了一组消息,以队列的形式对外提供插入和删除的工作。 虽然叫消息队列,但是它的内部存储结构并不是真正的队列,

而是采用单链表的数据结构来存储消息列表。 Looper的中文翻译为循环, 在这里可以理解为消息循环。由于 MessageQueue

只是一个消息的存储单元,它不能去处理消息,而 Looper 就填补了这个功能, Looper

会以无限循环的形式去查找是否有新消息,如果有的话就处理消息,否则就一直等待着。 Looper 中还有一个特殊的概念,那就是

ThreadLocal, ThreadLocal 并不是线程,它的作用是可以在每个线程中存储数据。我们知道, Handler

创建的时候会采用当前线程的 Looper 来构造消息循环系统,那么 Handler 内部如何获取到当前线程的 Looper 呢?

这就要使用 ThreadLocal 了,ThreadLocal可以在不同的线程中互不干扰地存储并提供数据,通过 ThreadLocal

可以轻松获取每个线程的 Looper。当然需要注意的是,线程是默认没有 Looper 的,如果需要使用 Handler 就必须为线程创建

Looper。我们经常提到的主线程,也叫 UI 线程,它就是ActivityThread,ActivityThread被创建时就会初始化

Looper,这也是在主线程中默认可以使用 Handler 的原因。 上面这段话是任玉刚老师书中对于android消息传递机制的描述我觉得描述的非常清晰。

android定下规则:只允许UI线程(主线程)修改Activity里的UI组件

但是应用中有时需要操作UI如获取短信验证码,有个倒计时,为此需要借助Handler消息传递机制

Handler类简介

【1】作用:

1在新启动的线程中发送消息

2在主线程中获取处理消息

主要方法

方法签名

public void handleMessage (Message msg)

子类对象通过该方法接收信息

public final boolean sendEmptyMessage (int what)

发送一个只含有what值的消息

public final boolean sendMessage (Message msg)

发送消息到Handler,通过handleMessage方法接收

public final boolean hasMessages (int what)

监测消息队列中是否还有what值的消息

public final boolean hasMessages (int what,Objectobject)

监测消息队列中是否还有what值的消息且object属性为制定对象的消息

public final boolean post (Runnable r)

将一个线程添加到消息队列

0818b9ca8b590ca3270a3433284dd417.png

下面一个倒计时例子

public class MainActivity extends Activity {

private Button button;

private int count;

private Message message;

private static final int TIME_DESC=0;

private Handler handler=new Handler(){

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

switch (message.what){

case TIME_DESC:

String time= (String) message.obj;

button.setText(time);

break;

}

}

} ;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

button= (Button) findViewById(R.id.button);

button.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

count=60;

new Thread(new Runnable() {

@Override

public void run() {

while(count>0){

count--;

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

message=new Message();

message.obj=count+"秒";

message.what=TIME_DESC;

handler.sendMessage(message);

}

}

}).start();

}

});

}

}

精简一下上面的代码如下

public class MainActivity2 extends Activity {

private Button button;

private int count;

private Message message;

private static final int TIME_DESC=0;

private Handler handler=new Handler(){

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

switch (message.what){

case TIME_DESC:

count--;

button.setText(count+"秒");

if(count>0){

handler.sendEmptyMessage(TIME_DESC);

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

break;

}

}

} ;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

button= (Button) findViewById(R.id.button);

//message初始化

message=new Message();

button.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

count=60;

handler.sendEmptyMessage(TIME_DESC);

}

});

}

}

Looper简介

Android中的Looper类,是用来封装消息循环和消息队列的一个类,用于在android线程中进行消息处理。handler其实可以看做是一个工具类,用来向消息队列中插入消息的。

(1) Looper类用来为一个线程开启一个消息循环。

默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。)

Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。

(2) 通常是通过Handler对象来与Looper进行交互的。Handler可看做是Looper的一个接口,用来向指定的Looper发送消息及定义处理方法。

默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。

mainHandler = new Handler() 等价于new Handler(Looper.myLooper()).

Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。

(3) 在非主线程中直接new Handler() 会报如下的错误:

E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception

E/AndroidRuntime( 6173): java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()

原因是非主线程中默认没有创建Looper对象,需要先调用Looper.prepare()启用Looper。

(4) Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。

注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

(5) 基于以上知识,可实现主线程给子线程(非主线程)发送消息。

public class MainActivity3 extends Activity {

private Button button_send;

private Handler handler;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.mainthreadsend);

handler=new Handler();

button_send = (Button) findViewById(R.id.button_send);

button_send.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

MyThread thread = new MyThread();

thread.start();

handler.sendEmptyMessage(0);

}

});

}

class MyThread extends Thread {

@Override

public void run() {

Looper.prepare();

handler = new Handler() {

@Override

public void handleMessage(Message msg) {

Log.d("handle", "收到主线程发送的消息");

}

};

Looper.loop();

}

}

}

结果

0818b9ca8b590ca3270a3433284dd417.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值