一、现象:子线程更新UI *** 作,竟然不崩溃二、原因:宽和高尺寸未变化,仅需替换text
2.1 当TextView宽和高尺寸未变化,则子线程调用setText,不崩溃!2.2 当TextView宽和高尺寸发生了变化,则子线程调用setText,崩溃! 三、分析:
上文中有两处不会调用requestLayout,另有两处会调用requestLayout。因为:mParent被ViewRootImpl赋值所以:mParent.requestLayout()调用的是ViewRootImpl.requestLayout()子线程更新UI会崩溃就是因为checkThread中的CalledFromWrongThreadException
一、现象:子线程更新UI *** 作,竟然不崩溃private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.tv); Button button = findViewById(R.id.btn); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread() { @Override public void run() { super.run(); //子线程更新UI:setText未崩溃 textView.setText("test"); } }.start(); } }); }二、原因:宽和高尺寸未变化,仅需替换text 2.1 当TextView宽和高尺寸未变化,则子线程调用setText,不崩溃! 2.2 当TextView宽和高尺寸发生了变化,则子线程调用setText,崩溃!
@UnsupportedAppUsage private void checkForRelayout() { // If we have a fixed width, we can just swap in a new text layout //如果固定了宽度,我们只需替换一个新的text layout。 // if the text height stays the same or if the view height is fixed. //如果高度不变,或者固定了高度。三、分析:
public class TextView extends View implements ... private void setText(CharSequence text, BufferType type, boolean notifyBefore, int oldlen) { ... if (mLayout != null) { checkForRelayout(); } ... }
public class TextView extends View implements ... @UnsupportedAppUsage 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 (...) { // Static width, so try making a new text layout. ... 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; } // 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; } } // We lose: the height has changed and we have a dynamic height. // Request a new view layout using our new text layout. requestLayout();//!!!这里才会checkThread invalidate(); } else { // Dynamic width, so we have no choice but to request a new // view layout with a new text layout. nullLayouts(); requestLayout();//!!!这里才会checkThread invalidate(); } }上文中有两处不会调用requestLayout, 另有两处会调用requestLayout。
只有需要新的view layout时,才需要调用requestLayout
(Request a new view layout using our new text layout.)
public class View implements ... public void requestLayout() { ... if (mParent != null && !mParent.isLayoutRequested()) { mParent.requestLayout(); } ... }因为:mParent被ViewRootImpl赋值
public class View implements ... void assignParent(ViewParent parent) { if (mParent == null) { mParent = parent; } ... }
public final class ViewRootImpl implements ViewParent, ... public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) { ... view.assignParent(this); ... }所以:mParent.requestLayout()调用的是ViewRootImpl.requestLayout()
public final class ViewRootImpl implements ViewParent, ... @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."); } }子线程更新UI会崩溃就是因为checkThread中的CalledFromWrongThreadException
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)