handler的应用场景
在安卓中,只有主线程才能进行UI操作。说明子线程内无法实现对UI的修改,因此安卓必然支持一种线程通信机制,使得子线程可以发消息让主线程改一下UI,该方案就是handler。
安卓中子线程之间也需要通信,通信方案也是handler。
消息机制
该通信机制分为四个部分:
message:线程中用来传递的信息载体。
messagequeue:存放消息的队列。通信机制是异步的,也就是说存放消息与取消息是独立的操作,本质上是一种生产者-消费者模式。
handler:接收器与发送器的实现。可以理解为是手机,手机可以发消息,也可以收消息。
looper:消息队列的循环调度器,负责将消息队列里面的消息自动分发给对应的接收器。
全部代码1
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实例。
扫描二维码关注公众号,回复:
14969626 查看本文章
本文的代码使用匿名内部类重写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对开发者来说是隐式存在的,程序中仅体现了发送与接收的过程。
全部代码2
使用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方法即可。