1. 可以在不同的线程中操作View吗?
不可以。
如果在其他不同的线程中操作View,比如:调用Button.setText(""),应用会因为抛出异常而崩溃。异常一般如下:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
2. Android为什么不让在多线程中更新UI?
如果是多线程可以更新UI的话,那则需要注意同步的问题。
如果解决同步问题,则需要进行加锁,获取引入其他的机制解决。
这样就会导致 性能下降,以及设计复杂。
Android针对UI的设计思想是:尽量保持简单、高效。而 使用单线程 就可以达到这样的效果。
3. 主线程 就是 UI线程吗?
最根本说法应该是:UI线程 就是创建(new)View对象的 所在的线程。
在“正常写代码”的情况下,主线程 可以认为是 UI线程。
“正常写代码”时,我们在onCreate中调用的setContentView,也就是在主线程中调用的setContentView。
而在setContentView的深层次代码中,是创建的 layout的view。
4. 主线程 就是 UI线程吗?
可以。但需要注意,在哪个线程创建的View,就只能在哪个线程更新View。
原因在于,最终在对View操作时,最终会调用到ViewRootImpl中requestLayout方法中,
而在这个方法中,会调用checkThread方法,这个方法会判断当前操作View的线程和创建View的线程是否是同一个,。
如果不是同一个,就会抛出异常。
5. 在子线程中创建UI并更新UI的示例代码:
public class SixActivity extends Activity {
private Button mThreadCreateButton;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_six);
findViewById(R.id.btn_ok).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
btnOkClick();
}
});
findViewById(R.id.btn_thread_click).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
btnThreadClick();
}
});
findViewById(R.id.btn_normal_click).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mThreadCreateButton.setText("error");
}
});
runThread();
}
private void btnThreadClick() {
new Thread(new Runnable() {
@Override
public void run() {
Message msg3 = Message.obtain();
msg3.what = 3;
handler.sendMessage(msg3);
}
}).start();
}
Handler handler;
private void btnOkClick() {
Message msg = Message.obtain();
msg.what = 1;
handler.sendMessage(msg);
}
private void runThread() {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
btnAdd();
} else if (msg.what == 3) {
mThreadCreateButton.setText("" + System.currentTimeMillis());
}
}
};
Looper.loop();
}
}).start();
}
private void btnAdd() {
mThreadCreateButton = new Button(this);
mThreadCreateButton.setText("新建的按钮");
mThreadCreateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mThreadCreateButton.setText("" + SystemClock.currentThreadTimeMillis());
}
});
WindowManager windowManager = getWindowManager();
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
1, 0, PixelFormat.OPAQUE);
lp.flags = WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
lp.gravity = Gravity.CENTER;
windowManager.addView(mThreadCreateButton, lp);
}
}