文章目录

概念介绍

【消息机制中的角色】
Message:消息的载体,用于封装消息的相关数据
Handler:消息的发送者与处理者,用于发送消息,并处理消息
MessageQueue:(在编程时不会使用到)消息队列,若干个消息的容器
Looper:轮询者,从消息队列中获取数据,并交给运行在主线程的 Handler 进行处理

xml
xml中增加一个按钮来发送消息

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
android:id="@+id/btn_send_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发出消息" />

</LinearLayout>

MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btnSendMsg;
private Handler handler;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

btnSendMsg = findViewById(R.id.btn_send_msg);
btnSendMsg.setOnClickListener(this);
handler = new Handler(new InnerHandlerCallback());
}

@Override
public void onClick(View view) {
//发出消息
Message msg = Message.obtain(handler);
msg.sendToTarget();
Log.d("Handler", "[Thread ID:]" + Thread.currentThread().getId() + " MainActivity onclick()->send message");
}

private class InnerHandlerCallback implements Handler.Callback {

@Override
public boolean handleMessage(Message message) {
Log.d("Handler", "[Thread ID:]" + Thread.currentThread().getId() + " InnerHandlerCallback handleMessage()->handle message");
return false;
}
}
}

运行程序,查看日志,从日志可以看出 Handler 是运行在主线程的
【达内课程】线程中Handler与Looper_looper
现在修改 onClick 中代码,把发送消息放在子线程中

@Override
public void onClick(View view) {
new Thread() {
@Override
public void run() {
//发出消息
Message msg = Message.obtain(handler);
msg.sendToTarget();
Log.d("Handler", "[Thread ID:]" + Thread.currentThread().getId() + " MainActivity onclick()->send message");
}
}.start();
}

运行程序,查看日志,可以看到发消息在子线程,处理消息还是在主线程
【达内课程】线程中Handler与Looper_android_02
如果把创建 Handler 也放在子线程中

@Override
protected void onCreate(Bundle savedInstanceState) {
......
new Thread() {
@Override
public void run() {
Looper.prepare();
handler = new Handler(new InnerHandlerCallback());
Log.d("Handler", "[Thread ID:]" + Thread.currentThread().getId() + " MainActivity onCreate()->sub thread->new Handler");
Looper.loop();
}
}.start();
}

运行程序,观察日志,会发现 handle message 是同一个线程:
【达内课程】线程中Handler与Looper_子线程_03
【Handler与Looper】
Handler 运行在哪个线程(在哪个线程上处理消息),取决于创建 Handler 时,关联到哪个线程上的 Looper,如果没有显示指定 Looper,则关联到当前线程

【小结】
1、在主线程创建的 Handler 对象,是运行在主线程的,所以可以直接更新 UI
2、在子线程中创建 Handler 之前,必须调用 ​​​Looper.prepare()​​​以初始化运行在子线程中的 Looper
3、在子线程中的 Looper 必须显式的调用 ​​​Looper.loop()​​​方法,才会开始轮询消息队列
4、在主线程中,默认就已经存在处于轮循工作状态的 Looper,而子线程中没有
5、如果没有可用的 Looper,则无法创建 Handler
6、创建 Handler 时,会默认关联当前线程上的 Looper

MessageQueue 是消息队列的意思,它主要用于存放所有通过 Handler 发送的消息。 这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个 MessageQueue 对象

Looper 是每个线程中的 MessageQueue 的管家,调用 Looper 的 ​​loop()​​​方法后,就会进入到一个无限循环当中,然后每当发现 MessageQueue 中存在一条消息,就会将它取出,并传递到 Handler 的 ​​handleMessage()​​方法中。每个线程中也只会有一个 Looper 对象