更新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的判断拉,所以就不会报错了呢。