Android里子线程真的不能刷新UI吗?

2026年09月26日 15:29
有2个网友回答
网友(1):

如果你在网上搜索CalledFromWrongThreadException:Only the original thread that created a view hierarchy can touch its views. 那么你肯定能看到很多文章说Android里子线程不能刷新UI。这句话不能说错,只是有些不太严谨。其实线程能否刷新UI的关键在于ViewRoot是否属于该线程。 让我们一起看看代码吧! 首先,CalledFromWrongThreadException这个异常是有下面的代码抛出的: void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); }}该段代码出自 framework/base/core/java/android/view/ViewRoot.java 其次,看看RootView的构造函数: public ViewRoot(Context context) { super(); if (MEASURE_LATENCY && lt == null) { lt = new LatencyTimer(100, 1000); } // For debug only //++sInstanceCount; // Initialize the statics when this class is first instantiated. This is // done here instead of in the static block because Zygote does not // allow the spawning of threads. getWindowSession(context.getMainLooper()); mThread = Thread.currentThread(); mLocation = new WindowLeaked(null); mLocation.fillInStackTrace(); mWidth = -1; mHeight = -1; mDirty = new Rect(); mTempRect = new Rect(); mVisRect = new Rect(); mWinFrame = new Rect(); mWindow = new W(this, context); mInputMethodCallback = new InputMethodCallback(this); mViewVisibility = View.GONE; mTransparentRegion = new Region(); mPreviousTransparentRegion = new Region(); mFirst = true; // true for the first time the view is added mAdded = false; mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this); mViewConfiguration = ViewConfiguration.get(context); mDensity = context.getResources().getDisplayMetrics().densityDpi; } 最后,我们看看ViewRoot.checkThread的调用顺序:com.david.test.helloworld.MainActivity$TestThread2.run -> android.widget.TextView.setText -> android.widget.TextView.checkForRelayout -> android.view.View.invalidate -> android.view.ViewGroup.invalidateChild -> android.view.ViewRoot.invalidateChildInParent -> android.view.ViewRoot.invalidateChild -> android.view.ViewRoot.checkThread

网友(2):

Android里子线程真刷新UI方法如下:

首先,CalledFromWrongThreadException这个异常是有下面的代码抛出的:

void checkThread() {

if (mThread != Thread.currentThread()) {

throw new CalledFromWrongThreadException(

"Only the original thread that created a view hierarchy can touch its views.");

}

}

该段代码出自 framework/base/core/java/android/view/ViewRoot.java

其次,看看RootView的构造函数:

public ViewRoot(Context context) {

super();

if (MEASURE_LATENCY && lt == null) {

lt = new LatencyTimer(100, 1000);

}

// For debug only

//++sInstanceCount;

// Initialize the statics when this class is first instantiated. This is

// done here instead of in the static block because Zygote does not

// allow the spawning of threads.

getWindowSession(context.getMainLooper());

mThread = Thread.currentThread();

mLocation = new WindowLeaked(null);

mLocation.fillInStackTrace();

mWidth = -1;

mHeight = -1;

mDirty = new Rect();

mTempRect = new Rect();

mVisRect = new Rect();

mWinFrame = new Rect();

mWindow = new W(this, context);

mInputMethodCallback = new InputMethodCallback(this);

mViewVisibility = View.GONE;

mTransparentRegion = new Region();

mPreviousTransparentRegion = new Region();

mFirst = true; // true for the first time the view is added

mAdded = false;

mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);

mViewConfiguration = ViewConfiguration.get(context);

mDensity = context.getResources().getDisplayMetrics().densityDpi;

}

最后,我们看看ViewRoot.checkThread的调用顺序:

com.david.test.helloworld.MainActivity$TestThread2.run

-> android.widget.TextView.setText

-> android.widget.TextView.checkForRelayout

-> android.view.View.invalidate

-> android.view.ViewGroup.invalidateChild

-> android.view.ViewRoot.invalidateChildInParent

-> android.view.ViewRoot.invalidateChild

-> android.view.ViewRoot.checkThread

linux