Android的消息传递机制是另外一种形式的“事件处理”,这种机制主要是为了解决Android应用中多线程的问题,在Android中不允许工作线程访问该Activity里的UI组件,这样会工作线程无法改变UI组件的属性值。但实际开发中,很多地方需要在 工作线程中改变UI组件的属性值,比如下载网络图片、动画等等。本篇博客主要介绍Handler是如何发送与处理线程上传递来的消息,以一个Button和一个TextView为例,点击Button会让TextView自动显示随机数字。由于现在鄙人学的还不是很好,一些表达是在别处借鉴来的哦。。。
1、Handler
它直接继承自Object,一个Handler允许发送和处理Message或者Runnable对象,并且会关联到主线程的MessageQueue 中。每个Handler具有一个单独的线程,并且关联到一个消息队列的线程,就是说一个Handler有一个固有的消息队列。当实例化一个Handler 的时候,它就承载在一个线程和消息队列的线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出 Message或Runnable,进而操作它们。
2、Handler主要有两个作用:
在工作线程中发送消息。
在UI线程中获取、处理消息。
3、Handler把压入消息队列有两大体系
上面介绍到Handler可以把一个Message对象或者Runnable对象压入到消息队列中,进而在UI线程中获取Message或者执行Runnable对象,所以Handler把压入消息队列有两大体系,Post和sendMessage:
post方式:Post方式允许把一个Runable对象压入到消息队列中。
sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。
post
它会传递一个Runnable对象到消息队列中,在这个Runnable对象中,重写run()方法。一般在这个run()方法中写入需要在UI线程上的操作。
下面是一个小小的Demo,点击Button,会一直出现随机数字
package com.example.xiaofeng1015.handler_post;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.Random;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btnStart;
private TextView textView;
// 定义一个Handler对象
private static Handler myHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnStart = (Button) findViewById(R.id.btnStart);
textView = (TextView) findViewById(R.id.tv01);
myHandler = new Handler();
btnStart.setOnClickListener(this);
}
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
while(true){
Random random = new Random(System.currentTimeMillis());
final int value = random.nextInt();
// Post方式工作与UI线程中
myHandler.post(new Runnable() {
@Override
public void run() {
textView.setText(Integer.toString(value));
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
sendMessage
Handler如果使用sendMessage方式把消息入队到消息队列中,需要传递一个Message对象,在Handler中,需要重写handlerMessage()方法,此方法在UI线程中执行。
简单介绍Message
Message继承Object,是一个public final类,所以不可被继承。Message封装了线程中传递的消息,如果对于一般的数据,Message提供了getData()和setData()方法来获取与设置数据,其中操作的数据是一个Bundle对 象,这个Bundle对象提供一系列的getXxx()和setXxx()方法用于传递基本数据类型的键值对。由于现在目前学的还不是很好,对于Message的复杂的数据的处理,还不做解释,嘻嘻。
下面是一个小小的Demo,点击Button,会一直出现随机数字
package com.example.xiaofeng1015.thread_app;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.Random;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btnStart;
private TextView textView;
private MyHandler myHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnStart = (Button) findViewById(R.id.btnSatrt);
textView = (TextView) findViewById(R.id.tv01);
myHandler = new MyHandler();
btnStart.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnSatrt:
// 开启一个线程来执行TextView产生随机数字
Thread myThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
// 产生一个随机数,以当前时间距离与开始的时间间隔为种子
Random random = new Random(System.currentTimeMillis());
int values = random.nextInt();
Message msg = new Message();
// 对消息进行标识
msg.what = 1;
// 创建Bundle,存储传递的数据
Bundle data = new Bundle();
// key-value形式
data.putInt("random", values);
msg.setData(data);
myHandler.sendMessage(msg);
try {
// 1s中执行一次
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
myThread.start();
break;
}
}
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what){
case 1:
Bundle data = msg.getData();
int value = data.getInt("random");
textView.setText(Integer.toString(value));
break;
}
}
}
}
结果显示:
到这里就介绍结束了,如果有什么需要改正的地方,还望大家多多提出呦!