使用HandlerThread获取Looper对象,后创建Handler(mHandlerThread.getLooper),此时的HandleMessage()在子线程中运行,为何此处可以更新UI?
public class MainActivity extends AppCompatActivity {
private TextView mTvText ;
private Handler mHandler;
// 使用这个新线程获取Looper对象
private HandlerThread mHandlerThread = new HandlerThread("my_handler_thread");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTvText = (TextView)findViewById(R.id.id_tv_text);
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
// 此处显示在子线程中执行 handleMessage()
// 为何在此处(子线程中)更新UI组件不会抛出异常?
Log.v("LOG","CurThread: "+Thread.currentThread());
// CurThread:Thread[my_handler_thread,5,Main]
mTvText.setText("update this textView!");
}
};
mHandler.sendEmptyMessage(1);
}
}
题主的代码确实是在子线程中更新的,可以打印 thread id 验证:
`// Use the provided Looper instead of the default one.
public Handler(Looper looper) {}`
所以在子线程中常常可以通过如下方法获取主线程的 handler,也可以使用题主的方法在主线程中获取子线程的 handler:
`// 这是一个主线程的 handler
new Handler(getContext().getMainLooper());`
至于为什么没有crash,确实很奇怪,我去查了 setText,实在复杂,没有看出端倪,但是倘若这样去做,会 crash:
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendEmptyMessage(1);
}
});
crash log 如下:
FATAL EXCEPTION: my_handler_thread
Process: com.magellan.mapdemo, PID: 2302
android.view.ViewRootImpl$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.
......
at android.widget.TextView.setText(TextView.java:4862)
所以我猜,crash 的关键词是 touch .
结论:不应该在子线程中更新UI,非常危险!
参考:http://stackoverflow.com/questions/14220883/accessing-ui-view-in-another-thread-does-not-cause-a-crash-why
http://www.codes9.com/mobile-development/android/about-the-update-ui-control-does-not-ui-in-non-crash-thread-problems/
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。