Android 常见面试问题整理

Author Avatar
dev.liang 4月 10, 2019
  • 在其它设备中阅读本文章

对 Android 面试常见问题点进行总结分析,方便对碎片知识进行回顾
Android 基础常见面试问题的整理,会持续更新…

Handler

说下 handler 机制,Looper 通过 MessageQueue 取消息,消息队列是先进先出模式,那我延迟发两个消息,第一个消息延迟 2 个小时,第二个消息延迟 1 个小时,那么第二个消息需要等 3 个小时才能取到吗?

参考:https://www.jianshu.com/p/558ed68d6888

MessageQueue 的实现不是队列,不要被名称迷惑,他是一个链表;每次发送消息都会按照 delay 值从小到大进行重排;所有的 delay 消息都是并行的,不是串行的;第一个延迟 2 个小时,第二个延迟 1 小时,会优先执行第二个,再过 1 小时执行第一个。

Android 为什么不能在子线程更新 UI ?

谷歌提出:“一定要在主线程更新UI”,实际是为了提高界面的效率和安全性,带来更好的流畅性;
反推一下,假如允许多线程更新UI,但是访问 UI 是没有加锁的,一旦多线程抢占了资源,那么界面将会乱套更新了,体验效果就不言而喻了;
UI 控件是非线程安全,在多线程中并发访问可能会导致UI控件处于不可预期的状态。所以在Android中规定必须在主线程更新UI。

不对 UI 控件的访问加上锁机制的原因?

上锁会让UI控件变得复杂和低效;
上锁后会阻塞某些进程的执行;

在 Activity 的 onCreate 里开一个子线程更新 UI,可以运行吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MainActivity extends Activity {  
private TextView tvText;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvText = (TextView) findViewById(R.id.main_tv);
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
tvText.setText("OtherThread");
}
}).start();
}
}

事件结果是可以运行。

原因如下

1
2
3
4
5
6
7
8
9
10
11
12
13
public final class ViewRootImpl implements ViewParent,  
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
// 省略代码…………………………

void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}

// 省略代码……………………
}

ViewRootImpl 对象是在 onResume 方法回调之后才创建,那么就说明了为什么在生命周期的 onCreate() 方法里,甚至是 onResume() 方法里都可以实现子线程更新 UI,因为此时还没有创建 ViewRootImpl 对象,并不会进行是否为主线程的判断, 也就是 ViewRootImpl 的 checkThread() 会检查,而 ViewRootImpl 是在 onResume() 方法里创建。onCreate() 里还没有创建 ViewRootImpl,所以不会抛出异常。

如果耗时的话,才会抛出异常,可以尝试让线程休眠 100ms or 1000ms。