Android Handler之更新ui使用分析


在Android中Handler相信你们都很熟悉了,主要用在:将工做线程中须要操做UI的消息传递到主线程,主线程收到消息后根据需求更新UI。java

这里举个例子看下:android

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ide

activity_main2
);
mBtn = findViewById(R.id.
text
);
new Thread(){
@Override
public void run() {
super.run();
Log.
e
(TAG,"My Thread running");
mBtn.setText("hello");
}
}.start();
}


这里咱们直接在onCreate方法中建立一个子线程,并更新UI, 这时候跑下程序会发现,程序正常运行,而且ui也更新了,这是为何呢?不是说不能在子线程更新ui吗?oop

其实这是一个比较特殊的状况,经过源码知道子线程更新ui报的异常是在android.view.ViewRootImpl中抛出的:post

void checkThread() {
if (mThread != Thread.ui

currentThread
()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}

}线程

而ViewRootImpl的建立是在onResume方法以后的,因此直接在onCreate建立子线程更新ui并不会抛出异常。cdn

接下来咱们改下例子:对象

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.blog

activity_main2
);
mBtn = findViewById(R.id.
text
);
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startThread();
}
});
}

private void startThread(){
new Thread(){
@Override
public void run() {
super.run();
Log.
e
(TAG,"My Thread running");
mBtn.setText("hello");
}
}.start();

}

这里咱们把子线程放到点击事件中开启,运行程序,点击button,这是发现抛出异常了:


这就是ViewRootImpl中要求不能再子线程中更新ui抛出的异常信息。

那么咱们若是要在子线程中更新Ui要怎么作呢?这就是咱们要介绍的Handler,这里咱们分两种状况来使用

1.直接在子线程中new Handler代码以下:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.

activity_main2
);
mBtn = findViewById(R.id.
text
);
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startThread();
}
});
}

private void startThread(){
new Thread(){
@Override
public void run() {
super.run();
Log.
e
(TAG,"My Thread running");
new Handler().post(new Runnable() {
@Override
public void run() {
mBtn.setText("hello");
}
});
}
}.start();

}

跑下程序,发现崩了:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

at android.os.Handler.<init>(Handler.java:200)

at android.os.Handler.<init>(Handler.java:114)

这是由于Android系统默认状况下非主线程中没有开启Looper,而Handler对象必须绑定Looper对象。

咱们修改下代码:

new Thread(){
@Override
public void run() {
super.run();
Log.

e
(TAG,"My Thread running");
new Handler(getMainLooper()).post(new Runnable() {
@Override
public void run() {
mBtn.setText("hello");
}
});
}

}.start();

在Handler中加入getMainLooper()方法,把它绑定到主线程的looper这样跑下程序,发现能够了。

2.在主线程中new Handler:

mHandler = new Handler();
mBtn = findViewById(R.id.

text
);
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startThread();
}
});
}

private void startThread(){
new Thread(){
@Override
public void run() {
super.run();
Log.
e
(TAG,"My Thread running");
mHandler.post(new Runnable() {
@Override
public void run() {
mBtn.setText("hello");
}
});
}
}.start();

}

这样跑起来也是没问题的。

Android Handler的简单使用就介绍到这边,接下来一章,会结合源码来详细分析下Handler的机制。

相关文章
相关标签/搜索