上篇文章:子线程不显示Toast? 分析了子线程不显示Toast的原因,并通过Looper.prepare(); Looper.loop();
解决。这篇文章我们通过runOnUiThread()
解决,并分析原因。
本文:Android 12 api=32
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"子线程",Toast.LENGTH_SHORT).show();
}
});
}
}).start();
}
}
runOnUiThread()方法是Activity.java中的成员方法,被final
修饰,不能被重写。此方法内部,通过mHandler.post()
把Runnable发送出去了。这个mHandler
是Activity.java的成员变量,但是被@UnsupportedAppUsage
注解修饰,所以子类不能直接使用,需要自己实例化新的Handler对象。
Activity.java
// we must have a handler before the FragmentController is constructed
@UnsupportedAppUsage
final Handler mHandler = new Handler();
...
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
这个@UnsupportedAppUsage
注解是从Android 11®版本引入的,具体参考:@UnsupportedAppUsage注解。Android 6.0里面没有这个注解,源码如下。不过,看注释// we must have a handler before the FragmentController is constructed
,保险起见还是自己新实例化一个Handler对象。
Android 6.0 Activity.java
// we must have a handler before the FragmentController is constructed
final Handler mHandler = new Handler();
不扯远了。继续看Handler的post的方法。
//Handler.java
public final boolean post(@NonNull Runnable r) {
//这里通过getPostMessage() 把Runnable转为了一个Message对象
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
//Runnable 保存在Message的成员变量callback里面。
m.callback = r;
return m;
}
//Message.java
public final class Message implements Parcelable {
...
@UnsupportedAppUsage
/*package*/ Runnable callback;
...
}
总接一下:runOnUiThread()方法,是Activity的方法。它的入参Runnable最终被保存在了一个Message对象的callback变量里面,然后就和sendMessage()方法的流程一样了。