离面试不到 24 小时,怎么办?
不要慌,其实时间越近,反而我们不应该再去看一些新的面试知识,放平心态。准备一下面这些 Android 基础题。
1. 说下 Activity 的四种启动模式?
参考回答:
standard 标准模式:每次启动一个 Activity 就会创建一个新的实例
singleTop 栈顶复用模式:如果新 Activity 已经位于任务栈的栈顶,就不会重新创建,并回调
onNewIntent(intent) 方法
singleTask 栈内复用模式:只要该 Activity 在一个任务栈中存在,都不会重新创建,并回调
onNewIntent(intent) 方法。如果不存在,系统会先寻找是否存在需要的栈,如果不存在该栈,就创建一个任务栈,并把该 Activity 放进去;如果存在,就会创建到已经存在的栈中
singleInstance 单实例模式:具有此模式的Activity只能单独位于一个任务栈中,且此任务栈中只有唯一一个实例
2. Activity A启动另一个Activity B会回调哪些方法?如果Activity B是完全透明呢?如果启动的是一个Dialog呢?
参考回答:
Activity A 启动另一个 Activity B 会回调的方法:Activity A 的 onPause() --> Activity B 的onCreate()–>onStart()–>onResume()–>Activity A的 onStop();如果Activity B是完全透明的,则最后不会调用 Activity A 的 onStop();如果是对话框 Activity,同后种情况。
3. 谈一谈 Fragment 的生命周期?
参考回答:
Fragment 从创建到销毁整个生命周期中涉及到的方法依次为:onAttach()->onCreate()-> onCreateView()->onActivityCreated()->onStart()->onResume()->onPause()->onStop()->onDestroyView()->onDestroy()->onDetach(),其中和Activity有不少名称相同作用相似的方法,而不同的方法有:
onAttach():当Fragment和Activity建立关联时调用
onCreateView():当Fragment创建视图时调用
onActivityCreated():当与Fragment相关联的Activity完成onCreate()之后调用
onDestroyView():在Fragment中的布局被移除时调用
onDetach():当Fragment和Activity解除关联时调用。
4. Service的两种启动方式?区别在哪?
参考回答:
第一种,其他组件调用Context的 startService() 方法可以启动一个Service,并回调服务中的onStartCommand()。如果该服务之前还没创建,那么回调的顺序是onCreate()->onStartCommand()。服务启动了之后会一直保持运行状态,直到 stopService() 或 stopSelf() 方法被调用,服务停止并回调onDestroy()。另外,无论调用多少次startService()方法,只需调用一次stopService()或stopSelf()方法,服务就会停止了。
第二种,其它组件调用Context的 bindService() 可以绑定一个Service,并回调服务中的onBind()方法。类似地,如果该服务之前还没创建,那么回调的顺序是onCreate()->onBind()。之后,调用方可以获取到onBind()方法里返回的IBinder对象的实例,从而实现和服务进行通信。只要调用方和服务之间的连接没有断开,服务就会一直保持运行状态,直到调用了 unbindService() 方法服务会停止,回调顺序onUnBind()->onDestroy()。
5. 如何保证Service不被杀死?
参考回答:
可以采取以下几种解决方法:
在 Service 的onStartCommand()中设置flages值为START_STICKY,使得Service被杀死后尝试再次启动Service
提升Service优先级,比如设置为一个前台服务
在Activity的onDestroy()通过发送广播,并在广播接收器的onReceive()中启动Service。
6. 广播的两种注册形式?区别在哪?
参考回答:
广播的注册有两种方法:一种在活动里通过代码动态注册,另一种在配置文件里静态注册。两种方式的相同点是都完成了对接收器以及它能接收的广播值这两个值的定义;
不同点是动态注册的接收器必须要在程序启动之后才能接收到广播,而静态注册的接收器即便程序未启动也能接收到广播,比如想接收到手机开机完成后系统发出的广播就只能用静态注册了。
7. Android 中提供哪些数据持久存储的方法?
参考回答:
Android 平台实现数据存储的常见几种方式:
网络存储:即通过网络来实现数据的存储和获取,可以调用WebService返回的数据或是解析HTTP协议实现网络数据交互。
File 文件存储:写入和读取文件的方法和 Java中实现I/O的程序一样。
SharedPreferences存储:一种轻型的数据存储方式,常用来存储一些简单的配置信息,本质是基于XML文件存储key-value键值对数据。
SQLite数据库存储:一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,在存储大量复杂的关系型数据的时可以使用。
ContentProvider:四大组件之一,用于数据的存储和共享,不仅可以让不同应用程序之间进行数据共享,还可以选择只对哪一部分数据进行共享,可保证程序中的隐私数据不会有泄漏风险。
8. 谈一谈View的事件分发机制?
参考回答:
事件分发本质:就是对MotionEvent事件分发的过程。即当一个MotionEvent产生了以后,系统需要将这个点击事件传递到一个具体的View上。
点击事件的传递顺序:Activity(Window) -> ViewGroup -> View
三个主要方法:
dispatchTouchEvent:进行事件的分发(传递)。返回值是 boolean 类型,受当前onTouchEvent和下级view的dispatchTouchEvent影响
onInterceptTouchEvent:对事件进行拦截。该方法只在ViewGroup中有,View(不包含 ViewGroup)是没有的。一旦拦截,则执行ViewGroup的onTouchEvent,在ViewGroup中处理事件,而不接着分发给View。且只调用一次,所以后面的事件都会交给ViewGroup处理。
onTouchEvent:进行事件处理。
9. Android中有哪几种类型的动画?
参考回答:
常见三类动画:
View动画(View Animation)/补间动画(Tween animation):对View进行平移、缩放、旋转和透明度变化的动画,不能真正的改变view的位置。应用如布局动画、Activity切换动画
逐帧动画(Drawable Animation):是View动画的一种,它会按照顺序播放一组预先定义好的图片
属性动画(Property Animation):对该类对象进行动画操作,真正改变了对象的属性
10. Activity、View、Window三者之间的关系?
参考回答:
在Activity启动过程其中的attach()方法中初始化了PhoneWindow,而PhoneWindow是Window的唯一实现类,然后Activity通过setContentView将View设置到了PhoneWindow上,而View通过WindowManager的addView()、removeView()、updateViewLayout()对View进行管理。
11. 谈谈消息机制Hander?作用?有哪些要素?流程是怎样的?
参考回答:
作用:跨线程通信。当子线程中进行耗时操作后需要更新UI时,通过Handler将有关UI的操作切换到主线程中执行。
四要素:
Message(消息):需要被传递的消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,最终由Handler处理。
MessageQueue(消息队列):用来存放Handler发送过来的消息,内部通过单链表的数据结构来维护消息列表,等待Looper的抽取。
Handler(处理者):负责Message的发送及处理。通过 Handler.sendMessage() 向消息池发送各种消息事件;通过 Handler.handleMessage() 处理相应的消息事件。
Looper(消息泵):通过Looper.loop()不断地从MessageQueue中抽取Message,按分发机制将消息分发给目标处理者。
Handler.sendMessage()发送消息时,会通过MessageQueue.enqueueMessage()向MessageQueue中添加一条消息;
通过Looper.loop()开启循环后,不断轮询调用MessageQueue.next();
调用目标Handler.dispatchMessage()去传递消息,目标Handler收到消息后调用Handler.handlerMessage()处理消息。
12. 为什么系统不建议在子线程访问UI?
参考回答:
系统不建议在子线程访问UI的原因是,UI控件非线程安全,在多线程中并发访问可能会导致UI控件处于不可预期的状态。而不对UI控件的访问加上锁机制的原因有:
上锁会让UI控件变得复杂和低效
上锁后会阻塞某些进程的执行
13. HandlerThread有什么特点?
参考回答:
HandlerThread是一个线程类,它继承自Thread。与普通Thread不同,HandlerThread具有消息循环的效果,这是因为它内部HandlerThread.run()方法中有Looper,能通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环。
14. IntentService的特点?
参考回答:
不同于线程,IntentService是服务,优先级比线程高,更不容易被系统杀死,因此较适合执行一些高优先级的后台任务;不同于普通Service,IntentService可自动创建子线程来执行任务,且任务执行完毕后自动退出。
15. 什么是ANR?什么情况会出现ANR?如何避免?在不看代码的情况下如何快速定位出现ANR问题所在?
参考回答:
ANR(Application Not Responding,应用无响应):当操作在一段时间内系统无法处理时,会在系统层面会弹出ANR对话框
产生ANR可能是因为5s内无响应用户输入事件、10s内未结束BroadcastReceiver、20s内未结束Service
想要避免ANR就不要在主线程做耗时操作,而是通过开子线程,方法比如继承Thread或实现Runnable接口、使用AsyncTask、IntentService、HandlerThread等
16. 项目中如何做性能优化的?
思路:
举例说明项目注意了哪些方面的性能优化,如布局优化、绘制优化、内存泄漏优化、 响应速度优化、列表优化、Bitmap优化、 线程优化…
17. 了解哪些性能优化的工具?
思路:
做项目时是否使用过的系统自带的性能优化工具?公司是否有自己的性能优化工具?实现原理怎样的?
18. 内存泄漏是什么?为什么会发生?常见哪些内存泄漏的例子?都是怎么解决的?
参考回答:内存泄漏(Memory Leak)是指程序在申请内存后,无法释放已申请的内存空间。简单地说,发生内存泄漏是由于长周期对象持有对短周期对象的引用,使得短周期对象不能被及时回收。常见的几个例子和解决办法:
19. 内存泄漏和内存溢出的区别?
参考回答:
内存泄漏(Memory Leak)是指程序在申请内存后,无法释放已申请的内存空间。是造成应用程序OOM的主要原因之一。
内存溢出(out of memory)是指程序在申请内存时,没有足够的内存空间供其使用。
20. Android中为何新增Binder来作为主要的IPC方式?
参考回答:
Binder机制有什么几条优点:
传输效率高、可操作性强:传输效率主要影响因素是内存拷贝的次数,拷贝次数越少,传输速率越高。从Android进程架构角度分析:对于消息队列、Socket和管道来说,数据先从发送方的缓存区拷贝到内核开辟的缓存区中,再从内核缓存区拷贝到接收方的缓存区,一共两次拷贝,
而对于Binder来说,数据从发送方的缓存区拷贝到内核的缓存区,而接收方的缓存区与内核的缓存区是映射到同一块物理地址的,节省了一次数据拷贝的过程,
由于共享内存操作复杂,综合来看,Binder的传输效率是最好的。
实现C/S架构方便:Linux的众IPC方式除了Socket以外都不是基于C/S架构,而Socket主要用于网络间的通信且传输效率较低。Binder基于C/S架构 ,Server端与Client端相对独立,稳定性较好。
安全性高:传统Linux IPC的接收方无法获得对方进程可靠的UID/PID,从而无法鉴别对方身份;而Binder机制为每个进程分配了UID/PID且在Binder通信时会根据UID/PID进行有效性检测。