在文章的开头,大家可以试一下以下的代码:布局文件就是新建一个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操作
}
}
先就这样。。。。