线程间通讯所需要的五个类:
1.Message 存放 消息id,消息对应数据-->由MessageQueue统一队列-->最终由Handler处理
2.Handler 处理者 -->Message发送及处理 使用时要实现handleMessage(Message msg)
对特定Message处理 更新UI
3.MessageQueue 存放Handler发送的消息队列,按照FIFO(先进先出)规则执
4.Looper 消息泵 不断从MessageQueue中抽取Message
一个MessageQueue需要一个Looper,一一对应关系
5.Thread 调度整个消息 消息循环执行场所
简单原理解析
- 生成
Message msg = mHandler.obtainMessage();
msg.what = what;
msg.sendToTarget();
- 发送
MessageQueue queue = mQueue;
if(queue!=null){
msg.target = this;
sent = queue.enqueueMessage(msg,uptimeMillis);
}
Handler.java sendMessageAtTime(Message msg,long uptimeMillis)
找到它所引用的MessageQueue 然后将Message target设置成自己
为了在处理消息环节,Message 能找到正确Handler,再将这个Message纳入消息队列中
- 抽取
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while(true){
Message msg = queue.next();//might block
if(msg!=null){
//No target is a magic identifier for the quit message
return;
}
msg.target.dispatchMessage(msg);
msg.recycle(); //回收
}
Looper.java loop()函数 死循环,不断从MessageQueue中获取下一个Message(next()方法)
通过Message中携带的target 信息 交由正确的Handler处理(dispatchMessage方法)
- 处理
if(msg.callback!=null){
handleCallback(msg);
}else{
if(mCallback !=null){
if(mCallback.handleMessage(msg)){
return;
}
}
handleMessage(msg);
}
Handler.java dispatchMessage(Message msg)方法中,
其中一个分支 调用handleMessage 处理这条Message
所以使用Handler 时 需要实现handleMessage(Message msg)
Message由Handler发送 -->MessageQueue 入队
Looper抽取-->回到Handler同步操作-->异步
-Handler 、Looper、MessageQueue三角关系
Handler与Looper、MessageQueue简单聚集关系
多个Handler可以共用一个Looper MessageQueue 但是Handler就运行在同一个线程中了
通常Handler写法
class LooperThread extends Thread{
public Handler mHandler;
public void run(){
Looper.prepare();//1.创建handler前 为其准备好一个Looper
mHandler = new Handler(){
public void handlerMessage(Message msg){
//process incoming messages here
}
}
Looper.loop();//2.Looper跑起来 抽取Message 这样才能正常操作
}
}
-Handler 处理消息总是在创建Handler的线程里运行
其他线程访问UI线程方法
1.Activity.runOnUiThread(Runnable r)
2.View.post(Runnable r)//此方法中view获得当前线程的handler 一般UI线程
将action对象post到-->Handler里,在Handler中将传递来的 Action对象包装成Message,
将其投入UI线程消息循环中 Handler再次处理 消息循环时 有一个分支为他所设的
直接调用Runnable 的run方法 此时已经路由到UI线程里 所以可以处理UI了
3.View.postDelayed(Runnable r,long t);
4.Handler
案例:简单 主线程 子线程通讯
主线程的字符串-->子线程-->字符串进行拼接----回传-->主线程 显示在TextView中
package com.qiuxf.handler;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private TextView tv_show;
private Button btn_start;
private Handler mMainHandler;
private Handler mChildHandler;
public static final String TAG = "TAG";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_show = findViewById(R.id.tv_show);
btn_start = findViewById(R.id.btn_start);
mMainHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String fromChileString = (String) msg.obj;
tv_show.setText(fromChileString);
}
};
btn_start.setOnClickListener(new View.OnClickListener() {//主线程与子线程通讯
@Override
public void onClick(View v) {
if(mChildHandler!=null){
Message msg = new Message();
msg.obj = "from UI";
mChildHandler.sendMessage(msg);
}
}
});
new ChildThread().start();
}
private class ChildThread extends Thread{
@Override
public void run() {
Looper.prepare();//初始化消息队列所需要的资源和参数
mChildHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String fromUIStr = (String) msg.obj;
Log.d(TAG,"接收到UI:"+fromUIStr);
String toUIStr = fromUIStr + "-->I'm child";
Message msg2UI = new Message();
msg2UI.obj = toUIStr;
if(mMainHandler!=null){
mMainHandler .sendMessage(msg2UI);
}
}
};
Looper.loop();//开启消息队列
}
}
}
运行结果:
--案例来源于慕课网