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的機制。

相關文章
相關標籤/搜索