如果你看了我写的《Android里子线程真的不能刷新UI吗?》,会回答:不能。那么到底能不能呢?呵呵,其实是能的了。那么《Android里子线程真的不能刷新UI吗?》里写错了吗?嗯,没有。呵呵,相信大家看到这里一定是一头雾水,认为笔者自相矛盾了。

让我们看个实例吧:

package com.david.test.helloworld;

import android.app.Activity;

import android.os.Bundle;

import android.widget.Button;

public class TestActivity extends Activity {

Button btn = null;

/** Called when the activity is first created. */

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

btn = (Button) findViewById(R.id.Button01);

TestThread2 t = new TestThread2(btn);

t.start();

}

class TestThread2 extends Thread {

Button btn = null;

public TestThread2(Button btn) {

this.btn = btn;

}

@Override

public void run() {

btn.setText("TestThread2.run");

}

}

}

建立一个工程,将上述代码拷贝进去,运行看看吧! Btn的文本一定改变为"TestThread2.run"了。

那么这到底是怎么回事呢?当我发现这个问题时,也困惑了。经过一番调查后,真相大白。现在和大家分享一下。奥秘在于ViewRoot的建立时间,它是在ActivityThread.java的final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward)里创建的。

看看代码吧:

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {

// If we are getting ready to gc after going to the background, well

// we are back active so skip it.

unscheduleGcIdler();

ActivityRecord r = performResumeActivity(token, clearHide);

if (r != null) {

final Activity a = r.activity;

if (localLOGV) Slog.v(

TAG, "Resume " + r + " started activity: " +

a.mStartedActivity + ", hideForNow: " + r.hideForNow

+ ", finished: " + a.mFinished);

final int forwardBit = isForward ?

WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

// If the window hasn't yet been added to the window manager,

// and this guy didn't finish itself or start another activity,

// then go ahead and add the window.

boolean willBeVisible = !a.mStartedActivity;

if (!willBeVisible) {

try {

willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(

a.getActivityToken());

} catch (RemoteException e) {

}

}

if (r.window == null && !a.mFinished && willBeVisible) {

r.window = r.activity.getWindow();

View decor = r.window.getDecorView();

decor.setVisibility(View.INVISIBLE);

ViewManager wm = a.getWindowManager();

WindowManager.LayoutParams l = r.window.getAttributes();

a.mDecor = decor;

l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

l.softInputMode |= forwardBit;

if (a.mVisibleFromClient) {

a.mWindowAdded = true;

wm.addView(decor, l);

}

// If the window has already been added, but during resume

// we started another activity, then don't yet make the

// window visible.

} else if (!willBeVisible) {

if (localLOGV) Slog.v(

TAG, "Launch " + r + " mStartedActivity set");

r.hideForNow = true;

}

// The window is now visible if it has been added, we are not

// simply finishing, and we are not starting another activity.

if (!r.activity.mFinished && willBeVisible

&& r.activity.mDecor != null && !r.hideForNow) {

if (r.newConfig != null) {

if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity "

+ r.activityInfo.name + " with newConfig " + r.newConfig);

performConfigurationChanged(r.activity, r.newConfig);

r.newConfig = null;

}

if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward="

+ isForward);

WindowManager.LayoutParams l = r.window.getAttributes();

if ((l.softInputMode

& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)

!= forwardBit) {

l.softInputMode = (l.softInputMode

& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))

| forwardBit;

if (r.activity.mVisibleFromClient) {

ViewManager wm = a.getWindowManager();

View decor = r.window.getDecorView();

wm.updateViewLayout(decor, l);

}

}

r.activity.mVisibleFromServer = true;

mNumVisibleActivities++;

if (r.activity.mVisibleFromClient) {

r.activity.makeVisible();

}

}

r.nextIdle = mNewActivities;

mNewActivities = r;

if (localLOGV) Slog.v(

TAG, "Scheduling idle handler for " + r);

Looper.myQueue().addIdleHandler(new Idler());

} else {

// If an exception was thrown when trying to resume, then

// just end this activity.

try {

ActivityManagerNative.getDefault()

.finishActivity(token, Activity.RESULT_CANCELED, null);

} catch (RemoteException ex) {

}

}

}

呵呵,相信到了这里,看过《Android里子线程真的不能刷新UI吗?》的读者一定明白了。答案就是在Activity.onResume前,ViewRoot实例没有建立,所以没有ViewRoot.checkThread检查。而btn.setText时设定的文本却保留了下来,所以当ViewRoot真正去刷新界面时,就把"TestThread2.run"刷了出来!

最后,提个问题结束吧:activity.onStart里通过线程刷新UI能成功吗?别回答太快哟!好好想想!

更多相关文章

  1. Android之在子线程更新UI(超详细)
  2. Android 实例讲解 Spinner样式修改
  3. Android 线程间通信机制(ITC详解)
  4. Android开发实例——Hello World
  5. android中使用线程池和临时缓存优化网络图片加载
  6. android的UI操作单线程模型理解
  7. android handler 多线程demo

随机推荐

  1. Android(安卓)Develop Challenge
  2. Android入门学习笔记之人机用户界面
  3. Android绘制简单折线图的步骤
  4. 四.Android六种布局详细讲解
  5. android 百度地图3.0+常用操作
  6. 怎么去掉联系人、通话记录、拨号列表界面
  7. Android系统下如何在程序中对XML里面元素
  8. Android(安卓)读取资源文件实例详解
  9. APK_获取Android的APK包签名信息
  10. Android(安卓)屏幕设置