java – 在UI线程上修改视图时Android UI不会崩溃
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java – 在UI线程上修改视图时Android UI不会崩溃,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4507字,纯文字阅读大概需要7分钟。
内容图文
![java – 在UI线程上修改视图时Android UI不会崩溃](/upload/InfoBanner/zyjiaocheng/789/fa004311f89347f2bb0fd4070132402f.jpg)
场景:
我在测试片段中的线程时遇到了一个奇怪的问题.
我在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 – 在UI线程上修改视图时Android UI不会崩溃全部内容,希望文章能够帮你解决java – 在UI线程上修改视图时Android UI不会崩溃所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。