一 、Handler是什么?
主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作。
简单说Handler是Android SDK来处理异步消息的核心类。 子线程与主线程通过Handler来进行通信。子线程可以通过Handler来通知主线程进行UI更新。
二 、 为什么使用Handler?
Android的UI更新只能在UI线程。如果任意线程都可以更新UI的话,线程安全问题处理起来会相当麻烦复杂,就会出现页面错乱。所以就规定了Android的是单线程模型,只允许在UI线程更新UI操作。也就是在Android中更新Ui必须在主线程,在子线程更新Ui会报子线程不能修改UI异常。因此子线程想要=更新UI就需要通过handler来发送消息给UI线程,然后UI线程再去更新UI。
三 、handler的简单使用
倒计时的实现
1. activity_main.xml中的代码如下
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
2. MainActivity中的代码如下
package com.lx.handler;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private int totalTime = 120;
private TextView textView;
private Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
textView.setText(String.valueOf(totalTime));
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.tv_time);
textView.setText(String.valueOf(totalTime));
new Thread(new Runnable() {
@Override
public void run() {
while (totalTime > 0) {
SystemClock.sleep(1000);
totalTime--;
Message message = handler.obtainMessage();
message.what = 1;
handler.sendMessage(message);
}
}
}).start();
}
}
这样就简单实现了一个倒计时的功能。在子线程中通过handler发送一个消息(message)给主线程。主线程收到消息之后去更新UI。
关于handler发送消息的用法还有:
handler.sendMessageDelayed(message, 1000); // 发送延时消息
handler.sendEmptyMessage(1); // 发送空消息,参数是message的what值
handler.sendEmptyMessageDelayed(1, 1000);// 发送空延时消息,参数是message的what值
在子线程中还可以通过handler的post(Runnable runnable)或者postDelayed(Runnable runnable,long delayMillis)方法切换到主线程.
new Thread(new Runnable() {
@Override
public void run() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
// 这里是主线程,可以直接更新UI
}
}, 1000);
handler.post(new Runnable() {
@Override
public void run() {
// 这里是主线程,可以直接更新UI
}
});
}
}).start();
4、handler使用存在的性能问题
当我们使用handler的时候很多都是直接new Handler()直接使用
private Handler handler=new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
这样new会报警告的,查看警告是:
中文意思大概是:
这个处理程序类应该是静态的,否则可能会发生泄漏(匿名的android.os.Handler)。
由于这个处理程序被声明为一个内部类,它可以防止外部类被垃圾收集。如果处理程序使用Looper或MessageQueue来处理主线程以外的线程,那么就没有问题了。如果处理程序使用主线程的Looper或MessageQueue,则需要修复处理程序声明,如下所示:将处理程序声明为 静态类;在外 部类中,实例化对外部类的WeakReference,并在实例化处理程序时将该对象传递给处理程序;使用WeakReference对象对外部类的 所有成员进行引用。
说的很明显了,使用静态内部类来解决。
对上面倒计时的代码优化如下
package com.lx.handler;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.widget.TextView;
import java.lang.ref.WeakReference;
public class MainActivity extends AppCompatActivity {
private int totalTime = 120;
private TextView textView;
private MyHandler handler = new MyHandler(this);
private static class MyHandler extends Handler {
//对Activity的弱引用
private final WeakReference<MainActivity> mActivity;
public MyHandler(MainActivity activity) {
mActivity = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
MainActivity activity = mActivity.get();
if (activity != null) {
activity.textView.setText(String.valueOf(activity.totalTime));
}
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.tv_time);
textView.setText(String.valueOf(totalTime));
new Thread(new Runnable() {
@Override
public void run() {
while (totalTime > 0) {
SystemClock.sleep(1000);
totalTime--;
Message message = handler.obtainMessage();
message.what = 1;
handler.sendMessage(message);
}
}
}).start();
}
@Override
protected void onDestroy() {
super.onDestroy();
// activity 退出时移除handler的所有回调以及消息
handler.removeCallbacksAndMessages(null);
}
}