本文为作者学习笔记,如有误,请各位大佬指点
目录
一、同步异步
二、Java多线程通信
三、Handler是什么
四、Handler相关的类
五、Handler常用方法
1. 发送消息
2. 接收处理消息
3. 切换线程
六、使用Handler
使用Handler更新UI
使用Handler延时更新UI
使用Handler消息传递
使用Handler消息延迟传递
Handler移除功能
Handler消息拦截
七、Handler原理
八、线程、looper、messageQueue、Handler的数量级关系
九、Handler案例-倒计时
一、同步异步
同步:一个进程在执行某个请求时,如果该请求需要一段时间才能返回信息,那么这个进程会一直等待下去,直到收到返回信息才继续执行下去。
异步:异步是指进程不需要一直等待下去,而是继续执行下面的操作,不管其他进程的状态,当有信息返回的时候会通知进程进行处理,这样就可以提高执行的效率了,
并发:多个任务在同一个时间段进行,在同一时刻,其实只有一个任务在进行。即在一台处理器上“同时”(同时间段)处理多个任务。
并行:多个任务在同一时刻发生,把每一个任务分配给每一个处理器独立完成。在同一时刻,任务一定是同时运行。并行在多台处理器上分别同时处理多个任务。
二、Java多线程通信
Java 中有很多种方法实现线程之间相互通信访问数据,比如:
-
通过 synchronized 关键字以“上锁”机制实现线程间的通信。多个线程持 有同一个对象,他们可以访问同一个共享变量,利用 synchronized“上锁” 机制,哪个线程拿到了锁,它就可以对共享变量进行修改,从而实现了通信。
-
使用 Object 类的 wait/notify 机制,执行代码 obj.wait();后这个对象 obj 所在的线程进入阻塞状态,直到其他线程调用了 obj.notify();方法 后线程才会被唤醒。
三、Handler是什么
-
更新UI
当后台任务完成时,通过handler将结果发送到UI线程,以更新UI界面,比如显示加载完成的数据、更新进度条等。
-
实现消息传递和线程通信的
Android应用通常会涉及到多个线程的并发执行,通过Handler,在不同线程间发送消息和处理消息,实现线程间的通信,比如主线程和后台线程之间的通信。
-
解决多线程并发
假设如果在一个Activity当中,有多个线程去更新UI,并且都没有加锁机制,就会产生更新界面错乱。
如果对更新UI的操作都进行加锁处理又会使应用性能下降,
所以Android给我们提供了handler,只需要遵循这样的机制就可以了,根本不用去关心多线程问题,都是在主线程的消息队列当中去轮询处理的。
-
定时任务处理
可以使用Handler的postDelayed()方法来延迟执行代码块或发送延时消息。
这对于实现定时刷新、定时执行任务等场景非常有用。
四、Handler相关的类
Handler:发送和接收消息
Looper:轮询消息队列,一个线程只能有一个Looper
Message:消息实体
MessageQueue:消息队列 用于存储消息和管理消息
五、Handler常用方法
1. 发送消息
-
boolean sendMessage (Message msg)
发送一条消息
-
boolean sendMessageDelayed (Message msg, long sendMessageDelayed )
在过了 delayMillis 毫秒之后发送一条消息。
-
boolean sendMessageAtTime (Message msg, long uptimeMillis)
在具体指定的时间 uptimeMillis 发送一条消息。uptimeMillis 为系统开机到当 前的时间(毫秒)。
-
boolean sendEmptyMessage (int what)
发送一个只有消息标识 waht 的空消息。该方法适用于不需要传递具体消息只是 单独的发通知时。
boolean sendEmptyMessageDelayed (int what, long delayMillis)
在过了 delayMillis 毫秒之后发送一个只有消息标识 waht 的空消息。
-
boolean sendEmptyMessageAtTime (int what, long uptimeMillis)
在具体指定的时间 uptimeMillis 发送一个只有消息标识 waht 的空消息。 uptimeMillis 为系统开机到当前的时间(毫秒)
2. 接收处理消息
-
void handleMessage (Message msg)
处理消息的方法。该方法通常用于被重写。
-
final boolean hasMessages(int what)
检查消息队列中是否包含what属性为指定值的消息。
-
final boolean hasMessages(int what, Object object)
检查消息队列中是否包含what属性为指定值且object属性为指定对象的消息。
-
多个重载的Message obtainMessage()
获取消息。
3. 切换线程
-
boolean post (Runnable r)
Runnabler会运行在 handler 对象被创建的线程上。当我们在 UI 线程创建了 Handler 对象,在 Worker 线程调用 handler.post()方法时,Runnable 就会运行 在 UI 线程中。
-
boolean postAtTime (Runnable r, long uptimeMillis)
在具体指定的时间 uptimeMillis 让 Runnable 运行在 Handler对象被创建的线程 中。
-
boolean postDelayed(Runnable r, long delayMillis)
在具体指定的时间 delayMillis 之后让 Runnable 运行在 Handler 对象被创建的 线程中
六、使用Handler
使用Handler更新UI
-
定义handler
privite Handler handler = new Handler();
-
定义runnable
Runnable runnable = new Runnable(){ public void run(){ textView.setText("cx") } };
-
启动runable
handler.post(runnable);
使用Handler延时更新UI
-
定义handler
-
定义runnable
-
启动runable
handler.postDelayed(runnable,2000);//延时2秒更新UI
-
发送延时通知
handler.sendEmptyMessageDelayed(what,2000);
使用Handler消息传递
-
创建消息(可以创建不同类型的消息)
//Message mes = handler.obtainMessage() Messagae mes = new Message(); mes.arg1=66; mes.arg1=32; mes.obj="djka"; //发送消息 //或者mes.sendToTargrt(); handler.sendMessage(mes);
-
接收并处理消息
privite Handler handler = new Handler(){ public void handlerMessage(Message message){ textViw.setText( (String)message.obj + message.arg1 + message.arg2); } };
使用Handler消息延迟传递
-
创建消息(可以创建不同类型的消息)
handler.sendMessageDelayed(mes);
-
接收并处理消息
Handler移除功能
比如在延时更新UI过程中移除,只是UI不再显示,
handle.removeCallbacks(runnable);
Handler消息拦截
-
消息接收
private Handler handler = new Handler(new Callback() { public boolean handleMessage(Message msg) { Toast.makeText(getApplicationContext(), "1", 1).show(); return true;//返回false,执行完上面的代码在执行下面的;返回true,则不再执行下面的代码 } }){ public void handleMessage(Message msg) { Toast.makeText(getApplicationContext(), "2", 1).show(); } };
-
发送一个空消息
handler.sendEmptyMessage(1);
七、Handler原理
-
Handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息传给handler自己,MessageQueue就是一个存储消息的容器。
-
Handler
是消息处理器,负责接收和处理消息。
每个Handler实例都关联一个特定的线程,并与该线程的消息队列关联。
可以发送和处理消息,实现线程间的通信。
-
Message
Handler传递的消息对象,用于在不同线程之间传递数据。
包含要传递的数据和附加消息(消息类型、标志等)。
通过Handler的sendMessage()方法发送到目标线程的消息队列中,并在目标线程中被处理
-
Looper
消息循环器,用于管理线程的消息队列。
每个线程只能有一个Looper对象,负责不断地读取队列中的消息,并将消息通过Handler的dispatchMessage()传递给对用的Handler进行处理。
-
-
Handler工作原理
-
当一个线程需要使用Handler来处理消息时,首先创建一个Looper对象:
在ActivityThread中的main方法中,系统调用
Looper.prepareMainLooper()
,调用其prepare()创建一个与当前线程关联的消息队列。prepare(boolean quitAllowed) quitAllowed的作用是在创建MessageQueue时,标识消息队列是 否可以销毁, 主线程不可被销毁
-
通过Looper的loop()启动消息循环,读取消息队列中的消息。
-
当有消息通过Handler的sendMessage()发送到消息队列时,Looper会不断从消息队列中读取消息,并传递给对用的Handler进行处理。
-
Handler接收到消息后,调用自己的handleMessage()来处理消息。
-
Handler消息处理流程
message中callback是一个Runnable对象,如果callback不为空,则直接调用callback的 run方法,
否则判断mCallback是否为空,mCallback在Handler构造方法中初始化,在主线程通直接通过无参的构造方法new出来的为 null,所以会直接执行后面的handleMessage()方法。
public void dispatchMessage(Message msg) {
//callback在message的构造方法中初始化或者使用handler.post(Runnable)时候才不为空
if (msg.callback != null) {
handleCallback(msg);
} else {
//mCallback是一个Callback对象,通过无参的构造方法创建出来的handler,该属性为null,此段不执行
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//最终执行handleMessage方法
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
八、线程、looper、messageQueue、Handler的数量级关系
一个 Thread 只能有一个 Looper,一个 MessageQueen,可以有多个 Handler 以一个线程为基准,他们的数量级关系是: Thread(1) : Looper(1) : MessageQueue(1) : Handler(N)
九、Handler案例-倒计时
public class MainActivity extends AppCompatActivity {
private TextView tv_aaa;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_aaa = findViewById(R.id.tv_aaa);
//aaa();
handler1.postDelayed(runnable,1000);
}
/* private Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
//tv_aaa.setText(msg.obj.toString());
}
};*/
private int i=10;
private Handler handler1=new Handler();
private Runnable runnable=new Runnable() {
@Override
public void run() {
if (i > 0){
tv_aaa.setText(i--+"");
handler1.postDelayed(this,1000);
}else {
handler1.removeCallbacksAndMessages(null);
}
}
};
/*
private void aaa() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
for (int i = 10; i > 0; i--) {
Log.d("xx", "run: ");
Message message = new Message();
//message.what = 0;
message.obj = i;
handler.sendMessageDelayed(message, (10-i) * 1000);
}
}
}, 1000);
*/
/*
new Thread(
new Runnable() {
@Override
public void run() {
for (int i = 10; i > 0; i--) {
Log.d("xxz", "run: ");
Message message = new Message();
message.what = 0;
message.obj = i;
handler.sendMessageDelayed(message, 1000);
}
}
}
).start();*//*
}
*/
//Handler handler = new Handler(){
// @Override
// public void handleMessage(@NonNull Message msg) {
// super.handleMessage(msg);
// switch (msg.what){
// case 0:
// tv_aaa.setText(msg.obj+"");
// }
// }
//};
}