Handler几乎每个人都会用,但是如果面试被问到,相信也不是每个人都能回答出来,特别是大点公司,特别喜欢问原理,或者你工作3年以上,别人不再问你怎么用了,而是问你底层实现原理,不然怎么区分你是高级还是中级 ,不给你定级别,工资不好给啊,
Handler作用:主要用于异步消息的处理,那么可能好奇,什么是异步消息,我们在学线程这块就知道,线程一般是用于处理比较耗时的操作,就是结果不是马上就能看的见的而是等时间过了才能看到结果的就是异步了,也就是说我在子线程中发送消息,然后要在主线程或者UI线程去更新UI的操作,
第一个问题:为什么android源码设计一定要在UI线程更新UI
比如我在子线程更新UI操作,那么有四个线程我去更新TextView控件上的文字,学会多线程的知道这可能会造成结果不是你想要的,多线程有三大特性:原子性。可见性 有序性 ,如果多个线程去操作TextView的话就涉及到线程安全问题了,如果是不安全就不能保证TextView显示的文字是你想要的结果,如果想让多线程变成安全的,那么就要加锁去控制,一旦加锁必然会影响性能,还可能导致过度绘制,这就是上面的答案.
第二个问题:难道子线程一定不能更新UI么?
针对上面的问题 我们写个代码:
new Thread(){
@Override
public void run() {
super.run();
tv.setText("更新了");
}
}.start();
这个运行后是不会报错的,那我在线程中调用sleep()方法再试试
new Thread(){
@Override
public void run() {
SystemClock.sleep(3000);
tv.setText("我在子线程中更新了");
}
}.start();
还是不会报错, 为什么,我相信网上很多博客 没有讲到这点,我们找到TextView的setText()方法:最终会调用TextView的这个方法:
private void setText(CharSequence text, BufferType type,
boolean notifyBefore, int oldlen) {
而这个方法有一段代码:
if (mLayout != null) {
checkForRelayout();
}
这个mLayout是不会为空,这个是Layout对象,它是封装了一些view的属性,在TextView中mLayout是可以获取到的:
Layout layout = tv.getLayout();
如果在onCreate()方法中去获取肯定为null,相当于你去onCreate ()方法获取view的高度或者宽度一样为0 ,那么就要走checkForRelayout()方法,
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;
}
// 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();
invalidate();
} else {
// Dynamic width, so we have no choice but to request a new
// view layout with a new text layout.
nullLayouts();
requestLayout();
invalidate();
}
}
你会看到不管if还是else都会调用:
requestLayout();
invalidate();
但是请注意上面有return语句,如果执行走到return语句就不回调用了,
if (mEllipsize != TextUtils.TruncateAt.MARQUEE) {
// In a fixed-height view, so use our new text layout.
if (mLayoutParams.height != LayoutParams.WRAP_CONTENT
&& mLayoutParams.height !=