小米Android面试总结

3月30号参加小米Android系统开发的面试,感触颇深,特意做了一下总结。技术面试有三轮,而且有很多手写算法的操作。问的比较深,比较细,但是真正意义上并不是很难。

Android部分

1. 事件的处理机制

  • 事件的分发,从外到内:

调用Activity的dispatchTouchEvent()
—>ViewGroup 的dispatchTouchEvent()
—>某个点击的view的dispatchTouchEvent()

  • 事件的消费,从里到外:

调用绑定在某个点击的view对象的监听器上,
—->调用监听器的onTouch()
—->调用view对象的onTouchEvent()
—->ViewGroup 的onTouchEvent()
—>调用Activity的onTouchEvent()

一旦在消费的过程中,某一个方法返回true,表示消费了此事件。则不再继续向外传递。

2. Handler、Message、Looper的原理

具体原理看我的这篇博客:详解Message,Handler,MessageQueue,Looper的关系
这里要注意两点:
1) Looper的阻塞和唤醒以及message按照when属性排序
2) message通过target知道自己将会被那个handler处理。

3. 内存泄漏
主要是让你列举内存泄漏的情况:

1)资源未关闭,如cursor使用完后未调用cursor.close()
2)Bitmap未recycle()
3)文件操作,I/O流未关闭
4)Dialog/PopupWindow等导致的Window Leak
5)线程创建未使用静态内部类方式(非静态内部类持有外部类的引用)
6)Context被生命周期长的对象引用(如单例等)

4. ANR
在Android里,应用程序的响应是由ActivityManager和WindowManager服务系统服务监视的,当检测到下面三种情况的任何一种时,Android就会针对特定的应用程序显示ANR对话框。

1) Activity的UI在5秒内没有响应输入事件(例如,按键按下,屏幕触摸)–主要类型
2) BroadcastReceiver在10秒内没有执行完毕
3) Service在特定时间内(20秒内)无法处理完成–小概率类型

5. 单例模式
让你手写一个你认为最好最安全的单例,当然单例有五种,可以选择写”双重检验锁”或者“静态内部类”。这里我选择双重检验锁。
小米Android面试总结
说的时候注意三点就行了:

  • 第一次判空为了效率
  • 第二次判空为了安全
  • volatile修饰是为了禁止指令重排列

算法部分

反正算法部分不仅仅是要实现,还要考虑到时间复杂度和空间复杂度。

1. 遍历二叉树
前序、后序、中序,大家自己去看吧。
2. 给定一个int数组,找出出现次数最多的数字(出现次数超过数组长度的一半)
我答得是:创建一个足够大的数组,遍历一个数,把数组的数当做新建数组的下标,对应的数组元素的值就是该数出现的次数,这样遍历下来就可以直接输出了。这个不适合数比较大的情况。
网上流行的做法: 由于该数字的出现次数比所有其他数字出现次数的和还要多,因此可以考虑在遍历数组时保存两个值:一个是数组中的一个数字,一个是次数,。当遍历到下一个数字时,如果下一个数字与之前保存的数字相同,则次数加1,如果不同,则次数减1,如果次数为0,则需要保存下一个数字,并把次数设定为1。由于我们要找的数字出现的次数比其他所有数字的出现次数之和还要大,则要找的数字肯定是组后一次把次数设为1时对应的数字。该方法的时间复杂度为O(n),空间复杂度为O(1)。
3. 找到一个int有序数组中任意两个相加等于9的数并输出他们的下标。
先将数组排序,然后用两个指向数组的指针,一个从前往后扫描,一个从后往前扫描,记为first和last,如果 fist + last < sum 则将fist向前移动,如果fist + last > sum,则last向后移动。(面试官会提示用:快速排序思想)
4. 有400本书,a每次拿1~3本,b也每次拿1~3本,让a先拿并且a、b每次轮流拿。如何保证b拿到最后一本书?
我当时是这么回答的:让a先拿,b看着a拿多少,只要每次保证a和b拿的个数加起来等于4就行了。
5. 链表插入
这个很简单,就不赘述了。