更新UI的几种方式:
runOnUiThread;
Handler post;
handler sendMessage;
view post;
第一种方法:Handler post:
public class FiveActivity extends Activity {
private TextView textView;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.five);
textView = (TextView) findViewById(R.id.tv1);
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
@Override
public void run() {
textView.setText("更新完成");
}
});
}
}.start();
}
private TextView textView;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.five);
textView = (TextView) findViewById(R.id.tv1);
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
@Override
public void run() {
textView.setText("更新完成");
}
});
}
}.start();
}
}
理解:程序运行,然后直走,进入线程UI线程显示当前内容,子线程等待,然后通过,handler.post更新显示内容(在主线程中执行);
第二种方法handler sendMessage :
public class FiveActivity extends Activity {
private TextView textView;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
textView.setText("更新完成");
}
};
private void handler2(){
handler.sendEmptyMessage(1);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.five);
textView = (TextView) findViewById(R.id.tv1);
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
handler2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
private TextView textView;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
textView.setText("更新完成");
}
};
private void handler2(){
handler.sendEmptyMessage(1);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.five);
textView = (TextView) findViewById(R.id.tv1);
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
handler2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
理解:程序运行,UI线程显示当前内容,子线程运行到handler.sendEmptyMessage(1)时候,给handler发送指令,然后更新完成。其中testView.setText在主线程中运行,其他步骤在子线程中运行。
第三种方法runOnUiThread :
private void update(){
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("更新完成");
Log.d("test", "线程:" + Thread.currentThread());
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.five);
textView = (TextView) findViewById(R.id.tv1);
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
update();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("更新完成");
Log.d("test", "线程:" + Thread.currentThread());
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.five);
textView = (TextView) findViewById(R.id.tv1);
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
update();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
理解:程序运行——>执行子线程——>执行到update方法的时候,UI更新;(testView.setText在主线程中运行)
第四种方法view post :
private void viewUI(){
textView.post(new Runnable() {
@Override
public void run() {
textView.setText("更新完成");
Log.d("test", "线程:" + Thread.currentThread());
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.five);
textView = (TextView) findViewById(R.id.tv1);
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
viewUI();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
textView.post(new Runnable() {
@Override
public void run() {
textView.setText("更新完成");
Log.d("test", "线程:" + Thread.currentThread());
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.five);
textView = (TextView) findViewById(R.id.tv1);
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
viewUI();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
理解:程序运行——>执行子线程——>执行到viewUI方法的时候,UI更新;(testView.setText在主线程中运行)
非UI线程更新UI的方法:
public class SixActivity extends Activity {
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.six);
textView= (TextView) findViewById(R.id.textView2);
new Thread(){
@Override
public void run() {
textView.setText("就更新你了,咋地");
Log.d("test","线程:"+Thread.currentThread());
}
}.start();
}
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.six);
textView= (TextView) findViewById(R.id.textView2);
new Thread(){
@Override
public void run() {
textView.setText("就更新你了,咋地");
Log.d("test","线程:"+Thread.currentThread());
}
}.start();
}
}
对,这就是非UI线程更新UI的方法,什么都别加 ,赤裸裸的。但是这是为什么呢,我们就一起去看看吧!
我们都知道,所有更新UI的方法,都会调用view的invalidate方法;
public void invalidate() {
invalidate(true);
invalidate(true);
}
void invalidate(boolean invalidateCache) {
invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
}
void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
boolean fullInvalidate) {
if (mGhostView != null) {
mGhostView.invalidate(true);
return;
}
if (skipInvalidate()) {
return;
}
if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)
|| (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)
|| (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED
|| (fullInvalidate && isOpaque() != mLastIsOpaque)) {
if (fullInvalidate) {
mLastIsOpaque = isOpaque();
mPrivateFlags &= ~PFLAG_DRAWN;
}
mPrivateFlags |= PFLAG_DIRTY;
if (invalidateCache) {
mPrivateFlags |= PFLAG_INVALIDATED;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
}
// Propagate the damage rectangle to the parent view.
final AttachInfo ai = mAttachInfo;
final ViewParent p = mParent;
if (p != null && ai != null && l < r && t < b) {
final Rect damage = ai.mTmpInvalRect;
damage.set(l, t, r, b);
p.invalidateChild(this, damage);
}
// Damage the entire projection receiver, if necessary.
if (mBackground != null && mBackground.isProjected()) {
final View receiver = getProjectionReceiver();
if (receiver != null) {
receiver.damageInParent();
}
}
// Damage the entire IsolatedZVolume receiving this view's shadow.
if (isHardwareAccelerated() && getZ() != 0) {
damageShadowReceiver();
}
}
invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
}
void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
boolean fullInvalidate) {
if (mGhostView != null) {
mGhostView.invalidate(true);
return;
}
if (skipInvalidate()) {
return;
}
if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)
|| (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)
|| (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED
|| (fullInvalidate && isOpaque() != mLastIsOpaque)) {
if (fullInvalidate) {
mLastIsOpaque = isOpaque();
mPrivateFlags &= ~PFLAG_DRAWN;
}
mPrivateFlags |= PFLAG_DIRTY;
if (invalidateCache) {
mPrivateFlags |= PFLAG_INVALIDATED;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
}
// Propagate the damage rectangle to the parent view.
final AttachInfo ai = mAttachInfo;
final ViewParent p = mParent;
if (p != null && ai != null && l < r && t < b) {
final Rect damage = ai.mTmpInvalRect;
damage.set(l, t, r, b);
p.invalidateChild(this, damage);
}
// Damage the entire projection receiver, if necessary.
if (mBackground != null && mBackground.isProjected()) {
final View receiver = getProjectionReceiver();
if (receiver != null) {
receiver.damageInParent();
}
}
// Damage the entire IsolatedZVolume receiving this view's shadow.
if (isHardwareAccelerated() && getZ() != 0) {
damageShadowReceiver();
}
}
}
其中关键的是ViewParent。然后,在ViewParent里面有个叫做InvalidateChildlnParent的方法,在这个方法中呢,有个checkThread的方法,这个就是拿来检查线程的;他的工作原理:在他的方法里面,会有一个判断,也就是
if(mThread!=Thread.curremtThread){
throw new Call………………………………(太长了,不想打了,就是用子线程更新UI而看到的异常。)
}
那么问题来了,当前线程没有休眠的时候呢,为什么就可以更新线程了呢?
那是因为Activity有个 ViewRootImpl他在onResume中创建,因为程序先走的是onCreate,所以,这ViewRootImpl 还没有被创建出来,也就不会进行
checkThread的判断拉,所以就不会报错了呢。