android 设置图片 ui线程 不显示,java – 在UI线程上修改视图时Android UI不会崩溃...

博客探讨了在Android中,为何在非主线程更新TextView的文本有时不会导致应用崩溃。作者比较了Kotlin和Java代码片段,发现崩溃只在Java版本中出现。问题在于TextView的`layout_width`属性:当设置为`wrap_content`时,更新文本可能不需要调用`requestLayout()`,从而绕过了主线程检查。因此,即使在非主线程修改UI,应用也不会崩溃。解决方案是确保所有UI操作都在主线程进行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

场景:

我在测试片段中的线程时遇到了一个奇怪的问题.

我在Kotlin中写了一个片段,其中包含onResume()中的以下片段:

override fun onResume() {

super.onResume()

val handlerThread = HandlerThread("Stuff")

handlerThread.start()

val handler = Handler(handlerThread.looper)

handler.post {

Thread.sleep(2000)

tv_name.setText("Something something : " + isMainThread())

}

}

是MainThread()是一个函数,它检查当前线程是否是主线程,如下所示:

private fun isMainThread(): Boolean = Looper.myLooper() == Looper.getMainLooper()

我看到我的TextView在2秒后更新了文本“Something something:false”

看到false告诉我这个线程当前不是UI / Main线程.

我认为这很奇怪,所以我创建了相同的片段,但用Java编写,而不是使用onResume()中的以下片段:

@Override

public void onResume() {

super.onResume();

HandlerThread handlerThread = new HandlerThread("stuff");

handlerThread.start();

new Handler(handlerThread.getLooper()).post(new Runnable() {

@Override

public void run() {

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

textView.setText("Something something...");

}

});

}

该应用程序崩溃,出现以下异常:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7313)

at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1161)

我做了一些研究,但我找不到能解释这一点的东西.另外,请假设我的观点全部正确充气.

题:

为什么我的应用程序在我在Kotlin编写的Fragment中运行我的UI线程的runnable中修改TextView时没有崩溃?

如果某些文档中有某些内容可以解释这一点,有人可以请我参考吗?

我实际上并没有尝试从UI线程修改我的UI,我只是好奇为什么会发生这种情况.

如果您需要更多信息,请告诉我.非常感谢!

更新:

根据@Hong Duan提到的,requestLayout()没有被调用.这与Kotlin / Java无关,而与TextView本身无关.

我傻了,并没有意识到我的Kotlin片段中的TextView的layout_width为“match_parent”.而我的Java片段中的TextView的layout_width为“wrap_content”.

TLDR:用户错误requestLayout(),其中并不总是发生线程检查.

解决方法:

CalledFromWrongThreadException仅在必要时抛出,但并非总是如此.在您的情况下,它会在ViewRootImpl.requestLayout()期间调用ViewRootImpl.checkThread()时抛出,这里是ViewRootImpl.java中的代码:

@Override

public void requestLayout() {

if (!mHandlingLayoutInLayoutRequest) {

checkThread();

mLayoutRequested = true;

scheduleTraversals();

}

}

void checkThread() {

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

throw new CalledFromWrongThreadException(

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

}

}

对于TextView,当我们更新它的文本时,并不总是需要重新布局,我们可以看到source code中的逻辑:

/**

* Check whether entirely new text requires a new view layout

* or merely a new text layout.

*/

private void checkForRelayout() {

// If we have a fixed width, we can just swap in a new text layout

// if the text height stays the same or if the view height is fixed.

if ((mLayoutParams.width != LayoutParams.WRAP_CONTENT

|| (mMaxWidthMode == mMinWidthMode && mMaxWidth == mMinWidth))

&& (mHint == null || mHintLayout != null)

&& (mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight() > 0)) {

// Static width, so try making a new text layout.

int oldht = mLayout.getHeight();

int want = mLayout.getWidth();

int hintWant = mHintLayout == null ? 0 : mHintLayout.getWidth();

/*

* No need to bring the text into view, since the size is not

* changing (unless we do the requestLayout(), in which case it

* will happen at measure).

*/

makeNewLayout(want, hintWant, UNKNOWN_BORING, UNKNOWN_BORING,

mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight(),

false);

if (mEllipsize != TextUtils.TruncateAt.MARQUEE) {

// In a fixed-height view, so use our new text layout.

if (mLayoutParams.height != LayoutParams.WRAP_CONTENT

&& mLayoutParams.height != LayoutParams.MATCH_PARENT) {

autoSizeText();

invalidate();

return; // return with out relayout

}

// Dynamic height, but height has stayed the same,

// so use our new text layout.

if (mLayout.getHeight() == oldht

&& (mHintLayout == null || mHintLayout.getHeight() == oldht)) {

autoSizeText();

invalidate();

return; // return with out relayout

}

}

// We lose: the height has changed and we have a dynamic height.

// Request a new view layout using our new text layout.

requestLayout();

invalidate();

} else {

// Dynamic width, so we have no choice but to request a new

// view layout with a new text layout.

nullLayouts();

requestLayout();

invalidate();

}

}

如您所见,在某些情况下,不会调用requestLayout(),因此不会引入主线程检查.

所以我认为关键点不是关于Kotlin或Java,而是关于TextViews的布局参数,它确定是否调用requestLayout().

标签:java,android,multithreading,kotlin

来源: https://codeday.me/bug/20190627/1303978.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值