在安卓中,只有主线程才能进行UI操作。说明子线程内无法实现对UI的修改,因此安卓必然支持一种线程通信机制,使得子线程可以发消息让主线程改一下UI,该方案就是handler。
安卓中子线程之间也需要通信,通信方案也是handler。
该通信机制分为四个部分:
message:线程中用来传递的信息载体。
messagequeue:存放消息的队列。通信机制是异步的,也就是说存放消息与取消息是独立的操作,本质上是一种生产者-消费者模式。
handler:接收器与发送器的实现。可以理解为是手机,手机可以发消息,也可以收消息。
looper:消息队列的循环调度器,负责将消息队列里面的消息自动分发给对应的接收器。
- package com.example.handlertest;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.annotation.SuppressLint;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
-
-
- public class MainActivity extends AppCompatActivity {
- private TextView textView;
- private Handler handler;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- TextView textView = findViewById(R.id.text1);
-
- //匿名内部类创建Handler对象
- handler = new Handler(){
- //重写handleMessage函数对收到的消息进行处理
- @Override
- public void handleMessage(Message message){
- switch (message.what){//根据消息标识进行处理
- case 1:
- textView.setText("Thread 1!");
- break;
- case 2:
- textView.setText("Thread 2!");
- break;
- default:
- break;
- }
- }
- };
-
- //创建新的子线程1
- new Thread(){
- @Override
- public void run(){
- try {
- //延时
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- //创建消息对象
- Message message = Message.obtain();
- //设定消息标识
- message.what = 1;
- //通过handler将消息发送到消息队列中
- handler.sendMessage(message);
- }
- }.start();//开启线程
-
-
- //创建新的子线程2
- new Thread(){
- @Override
- public void run(){
- try {
- //延时,和线程1错开
- Thread.sleep(4000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- //创建消息对象
- Message message = Message.obtain();
- //设定消息标识
- message.what = 2;
- //通过handler将消息发送到消息队列中
- handler.sendMessage(message);
- }
- }.start();//开启线程
- }
- }
通过两个线程先后发送消息,改变界面里文字的输出。
需要注意的是两个线程本身只执行一次,文字改变只有两次。
代码中存在三个线程,主线程以及自己设定的两个子线程。
private Handler handler;
但是handler对象只需要创建一个,因为进程内部的多个线程是共享内存的,三个线程用的是同一个handler实例。
本文的代码使用匿名内部类重写handler对象里收到信息后的处理函数handleMessage:
-
- //匿名内部类创建Handler对象
- handler = new Handler(){
- //重写handleMessage函数对收到的消息进行处理
- @Override
- public void handleMessage(Message message){
- switch (message.what){//根据消息标识进行处理
- case 1:
- textView.setText("Thread 1!");
- break;
- case 2:
- textView.setText("Thread 2!");
- break;
- default:
- break;
- }
- }
- };
该实例在主线程中创建,因此处理函数是在主线程进行的,可以进行UI修改。
也可以不使用匿名内部类,直接定义一种Handler的子类,并在主线程中创建一个对象。在该类的定义中实现对消息处理函数的重写。
- //创建消息对象
- Message message = Message.obtain();
- //设定消息标识
- message.what = 1;
- //通过handler将消息发送到消息队列中
- handler.sendMessage(message);
在子线程中只需要创建一个消息对象,设置消息内容,并发送到消息队列中即可。
消息队列messagequeue和循环控制器looper对开发者来说是隐式存在的,程序中仅体现了发送与接收的过程。
使用post的方式如下所示:
- package com.example.handlertest2;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.os.Bundle;
- import android.os.Handler;
- import android.widget.TextView;
-
- public class MainActivity extends AppCompatActivity {
- public TextView mTextView;
- public Handler mHandler;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- mTextView = (TextView) findViewById(R.id.text1);
-
- mHandler = new Handler();
-
- //第一个工作线程
- new Thread(){
- @Override
- public void run(){
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- //传入runnable对象进行发送
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mTextView.setText("Thread 1!");
- }
- });
- }
- }.start();
-
- //第二个工作线程
- new Thread(){
- @Override
- public void run(){
- try {
- Thread.sleep(4000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mTextView.setText("Thread 2!");
- }
- });
- }
- }.start();
- }
- }
第二种方法可以不对Handler进行重写,只需要调用其post方法即可。