//2023.12.12,本是比较简单的记录了一下,挺意外好几位收藏或点赞,所以补充一些,让内容详细点
使用子线程弹Toast,需要该子线程有Looper,不然会报错,比如我的代码是
new Thread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"test1",Toast.LENGTH_LONG).show();
}
}).start();
报错如下,这个是android7.1打印的堆栈
12-12 16:35:45.058 2250 2271 E AndroidRuntime: FATAL EXCEPTION: Thread-2
12-12 16:35:45.058 2250 2271 E AndroidRuntime: Process: com.example.administrator.myapplication, PID: 2250
12-12 16:35:45.058 2250 2271 E AndroidRuntime: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
12-12 16:35:45.058 2250 2271 E AndroidRuntime: at android.os.Handler.<init>(Handler.java:200)
12-12 16:35:45.058 2250 2271 E AndroidRuntime: at android.os.Handler.<init>(Handler.java:114)
12-12 16:35:45.058 2250 2271 E AndroidRuntime: at android.widget.Toast$TN$2.<init>(Toast.java:336)
12-12 16:35:45.058 2250 2271 E AndroidRuntime: at android.widget.Toast$TN.<init>(Toast.java:336)
12-12 16:35:45.058 2250 2271 E AndroidRuntime: at android.widget.Toast.<init>(Toast.java:103)
12-12 16:35:45.058 2250 2271 E AndroidRuntime: at android.widget.Toast.makeText(Toast.java:256)
12-12 16:35:45.058 2250 2271 E AndroidRuntime: at com.example.administrator.myapplication.MainActivity$2.run(MainActivity.java:258)
12-12 16:35:45.058 2250 2271 E AndroidRuntime: at java.lang.Thread.run(Thread.java:761)
这个是android11打印的堆栈
01-01 20:51:21.694 7241 7268 E AndroidRuntime: FATAL EXCEPTION: Thread-2
01-01 20:51:21.694 7241 7268 E AndroidRuntime: Process: com.example.administrator.myapplication, PID: 7241
01-01 20:51:21.694 7241 7268 E AndroidRuntime: java.lang.NullPointerException: Can't toast on a thread that has not called Looper.prepare()
01-01 20:51:21.694 7241 7268 E AndroidRuntime: at com.android.internal.util.Preconditions.checkNotNull(Preconditions.java:157)
01-01 20:51:21.694 7241 7268 E AndroidRuntime: at android.widget.Toast.getLooper(Toast.java:179)
01-01 20:51:21.694 7241 7268 E AndroidRuntime: at android.widget.Toast.<init>(Toast.java:164)
01-01 20:51:21.694 7241 7268 E AndroidRuntime: at android.widget.Toast.makeText(Toast.java:492)
01-01 20:51:21.694 7241 7268 E AndroidRuntime: at android.widget.Toast.makeText(Toast.java:480)
01-01 20:51:21.694 7241 7268 E AndroidRuntime: at com.example.administrator.myapplication.MainActivity$2.run(MainActivity.java:258)
01-01 20:51:21.694 7241 7268 E AndroidRuntime: at java.lang.Thread.run(Thread.java:923)
原因是相同的,需要该线程有Looper
android11上,在Toast.java中直接检查当前线程的Looper是否为空
return checkNotNull(Looper.myLooper(),
"Can't toast on a thread that has not called Looper.prepare()");
android7.1上,在Toast.java中需要创建handler
final Handler mHandler = new Handler()
在Handler.java中,会获取当前线程的Looper,并判断是否为空
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
添加个 Looper.prepare();不再报错,但也不会弹toast
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(MainActivity.this,"test1",Toast.LENGTH_LONG).show();
}
}).start();
再加上 Looper.loop();就可以正常弹toast了,这是因为Toast.java中显示toast是在handleMessage中处理的,不执行Looper.loop();消息不会送到handleMessage中处理
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(MainActivity.this,"test1",Toast.LENGTH_LONG).show();
Looper.loop();
}
}).start();
Looper.loop为死循环,阻塞,上面的方法只能该线程执行时弹一次toast,如果要多次弹toast,或某个条件达到让弹toast,最好把Toast.makeText()放在handleMessage中
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
threadHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
Log.d(TAG,"make a toast");
Toast.makeText(MainActivity.this,"test",Toast.LENGTH_LONG).show();
}
};
Looper.loop();
}
}).start();
参考文章:https://blog.youkuaiyun.com/tiangaopan/article/details/104791015/