在文章的開(kāi)頭,大家可以試一下以下的代碼:布局文件就是新建一個(gè)activity的時(shí)候生成的。
public class MainActivity extends AppCompatActivity {
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.textView);
new Thread(){
@Override
public void run() {
super.run();
mTextView.setText("huhu");
}
}.start();
}
}
是不是會(huì)驚奇的發(fā)現(xiàn)在工作線程中更新ui竟然成功了,而且不會(huì)報(bào)錯(cuò)。對(duì),你沒(méi)有看錯(cuò)就是可以。
然而如果這樣寫:先讓線程Thread.sleep()幾秒鐘,就會(huì)報(bào)錯(cuò)。這種情況先是在群里大哥出現(xiàn)了,然后在慕課網(wǎng)里面,專門花了一小節(jié)講了這件事。下面評(píng)論里總結(jié)的比我好,我來(lái)引用一下
更新UI-->會(huì)調(diào)用checkForRelayout()方法
-->invalidate()方法-->invalidate(true)方法,關(guān)注viewParent-->ViewRootImpl是ViewParent的實(shí)現(xiàn)類
--->p.invalidateChild()-->查看ViewRootImpl.invalidateChild()-->checkThread()方法-->判斷UI線程是否是當(dāng)前線程,不相等拋出異常。
ViewRootImpl是onResume()方法才會(huì)創(chuàng)建。所以onCreate()方法中要延遲才可以。
handleResumeActivity()方法--->viewManager.addView()-->ViewRootImpl初始化。關(guān)注viewParent-->ViewRootImpl是ViewParent的實(shí)現(xiàn)類
若看不懂用一句簡(jiǎn)單的話總結(jié)就是:在onResume()才會(huì)去檢查更新UI的線程是不是主線程,所以在onCreate()中啟動(dòng)線程更新UI也許不會(huì)報(bào)錯(cuò)。但是休眠就一定會(huì)。有了這個(gè),我們?cè)匍_(kāi)始講更新UI的操作(工作線程中)。
1、new Handler(Looper.getMainLooper()).post
new Thread(){
@Override
public void run() {
super.run();
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
mTextView.setText("ok");
}
});
}
}.start();
親測(cè)可以
2、runOnUiThread():在線程中執(zhí)行ui線程
new Thread(){
@Override
public void run() {
super.run();
runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText("今天是個(gè)好天氣");
}
});
}
}.start();
親測(cè)可以
3、View.post():
new Thread(){
@Override
public void run() {
super.run();
// Thread.sleep(1000);
mTextView.post(new Runnable() {
@Override
public void run() {
mTextView.setText("好像開(kāi)學(xué)了");
}
});
}
}.start();
好像沒(méi)什么變化,以上的我都是寫在onCreate方法中的,但是我先把線程休眠1秒鐘,神奇般的可以更新UI了,或者我把這個(gè)線程寫在onResume()中的時(shí)候又可以用了。
我簡(jiǎn)短的分析一下原因:其實(shí)我也分析不來(lái)什么原因啊,本來(lái)寫了一點(diǎn)但是我是真的說(shuō)不明白,就是深度不夠。簡(jiǎn)單說(shuō)一下,這個(gè)方法必須在onAttachToWindow()之后才執(zhí)行,那這個(gè)方法是在onResume()之后執(zhí)行。否則直接在onCreate()中,而且是在子線程中執(zhí)行的話,則永遠(yuǎn)都不會(huì)執(zhí)行到post里面。附上鏈接供以后拓展view.post()獲取寬高引發(fā)的兩個(gè)思考
4、view.postDelayed():和上面差不多,這個(gè)應(yīng)該就不會(huì)發(fā)生那些問(wèn)題。
5、AsyncTask
class Task extends AsyncTask{
@Override
protected void onPreExecute() {
super.onPreExecute();
//主線程,首先被執(zhí)行,可以進(jìn)行一些初始化操作。
}
@Override
protected Object doInBackground(Object[] params) {
//在onPreExecute()后執(zhí)行,運(yùn)行在子線程中
return null;
}
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
//主線程, 在doInBackground()后中執(zhí)行,
}
@Override
protected void onProgressUpdate(Object[] values) {
super.onProgressUpdate(values);
//更新progress操作
}
}
先就這樣。。。。