在文章的開頭,大家可以試一下以下的代碼:佈局文件就是新建一個activity的時候生成的。
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();
}
}
是不是會驚奇的發現在工作線程中更新ui竟然成功了,而且不會報錯。對,你沒有看錯就是可以。
然而如果這樣寫:先讓線程Thread.sleep()幾秒鐘,就會報錯。這種情況先是在羣裏大哥出現了,然後在慕課網裏面,專門花了一小節講了這件事。下面評論裏總結的比我好,我來引用一下
更新UI–>會調用checkForRelayout()方法
–>invalidate()方法–>invalidate(true)方法,關注viewParent–>ViewRootImpl是ViewParent的實現類
—>p.invalidateChild()–>查看ViewRootImpl.invalidateChild()–>checkThread()方法–>判斷UI線程是否是當前線程,不相等拋出異常。
ViewRootImpl是onResume()方法纔會創建。所以onCreate()方法中要延遲纔可以。
handleResumeActivity()方法—>viewManager.addView()–>ViewRootImpl初始化。關注viewParent–>ViewRootImpl是ViewParent的實現類
若看不懂用一句簡單的話總結就是:在onResume()纔會去檢查更新UI的線程是不是主線程,所以在onCreate()中啓動線程更新UI也許不會報錯。但是休眠就一定會。有了這個,我們再開始講更新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();
親測可以
2、runOnUiThread():在線程中執行ui線程
new Thread(){
@Override
public void run() {
super.run();
runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText("今天是個好天氣");
}
});
}
}.start();
親測可以
3、View.post():
new Thread(){
@Override
public void run() {
super.run();
// Thread.sleep(1000);
mTextView.post(new Runnable() {
@Override
public void run() {
mTextView.setText("好像開學了");
}
});
}
}.start();
好像沒什麼變化,以上的我都是寫在onCreate方法中的,但是我先把線程休眠1秒鐘,神奇般的可以更新UI了,或者我把這個線程寫在onResume()中的時候又可以用了。
我簡短的分析一下原因:其實我也分析不來什麼原因啊,本來寫了一點但是我是真的說不明白,就是深度不夠。簡單說一下,這個方法必須在onAttachToWindow()之後才執行,那這個方法是在onResume()之後執行。否則直接在onCreate()中,而且是在子線程中執行的話,則永遠都不會執行到post裏面。附上鍊接供以後拓展view.post()獲取寬高引發的兩個思考
4、view.postDelayed():和上面差不多,這個應該就不會發生那些問題。
5、AsyncTask
class Task extends AsyncTask{
@Override
protected void onPreExecute() {
super.onPreExecute();
//主線程,首先被執行,可以進行一些初始化操作。
}
@Override
protected Object doInBackground(Object[] params) {
//在onPreExecute()後執行,運行在子線程中
return null;
}
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
//主線程, 在doInBackground()後中執行,
}
@Override
protected void onProgressUpdate(Object[] values) {
super.onProgressUpdate(values);
//更新progress操作
}
}
先就這樣。。。。