2021年Android面试题知识点
- 1.前言
- 2.知识点
- 2.1、Activity和Fragment生命周期相关
- 2.2、android中进程的优先级问题
- 2.3、Bunder传递对象为什么需要序列化?Serialzable和Parcelable有什么区别?
- 2.4、Android动画相关
- 2.5、Context相关
- 2.6、Android各版本新特性
- 2.7、Asset目录与res目录的区别?
- 2.8、Handler机制
- 2.9、OOM 是否可以try catch
- 2.10、activty和Fragmengt之间怎么通信?Fragmengt和Fragmengt怎么通信?
- 2.11、服务启动一般有几种,服务和activty之间怎么通信,服务和服务之间怎么通信?
- 2.12、广播注册一般有几种,各有什么优缺点?
- 3.最后
1.前言
- 每年找工作的Android开发者都有不少人,想要找到一份更好的工作,不仅需要一份好的简历,更重要的是要熟练Android的每一个技术点、知识点。但是对于一部分开发来说,可能平常用到的东西不太会表达,这就有点吃亏了。
- 本篇博客是关于Android面试题一部分的总结,希望能够帮到你。
2.知识点
2.1、Activity和Fragment生命周期相关
2.2、android中进程的优先级问题
-
前台进程:
即与用户正在交互的Activity或者Activity用到的Service等,如果系统内存不足时前台进程是最晚被杀死的。 -
可见进程:
可以是处于暂停状态(onPause)的Activity或者绑定在其上的Service,即被用户可见,但由于失了焦点而不能与用户交互。 -
服务进程:
其中运行着使用startService方法启动的Service,虽然不被用户可见,但是却是用户关心的,例如用户正在非音乐界面听的音乐或者正在非下载页面下载的文件等;当系统要空间运行,前两者进程才会被终止。 -
后台进程:
其中运行着执行onStop方法而停止的程序,但是却不是用户当前关心的,例如后台挂着的QQ,这时的进程系统一旦没了有内存就首先被杀死。 -
空进程:
不包含任何应用程序的进程,这样的进程系统是一般不会让他存在的。
2.3、Bunder传递对象为什么需要序列化?Serialzable和Parcelable有什么区别?
因为bundle传递数据时只支持基本数据类型,所以在传递对象时需要序列化转换成可存储或可传输的本质状态(字节流)。序列化后的对象可以在网络、IPC(比如启动另一个进程的Activity、Service和Reciver)之间进行传输,也可以存储到本地。
-
Serializable(Java自带):
Serializable 是序列化的意思,表示将一个对象转换成存储或可传输的状态。序列化后的对象可以在网络上进传输,也可以存储到本地。 -
Parcelable(android专用):
除了Serializable之外,使用Parcelable也可以实现相同的效果,不过不同于将对象进行序列化,Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这也就实现传递对象的功能了。
区别总结如下图所示:
2.4、Android动画相关
-
帧动画
- 通过 AnimationDrawable 实现,容易 OOM
-
属性动画
属性动画有两个步聚:
1.计算属性值
2.为目标对象的属性设置属性值,即应用和刷新动画
过程一:
计算已完成动画分数 elapsed fraction。为了执行一个动画,你需要创建一个ValueAnimator,并且指定目标对象属性的开始、结束和持续时间。在调用 start 后的整个动画过程中,ValueAnimator 会根据已经完成的动画时间计算得到一个0 到 1 之间的分数,代表该动画的已完成动画百分比。0表示 0%,1 表示 100%。
过程二:
计算插值(动画变化率)interpolated fraction 。当 ValueAnimator计算完已完成的动画分数后,它会调用当前设置的TimeInterpolator,去计算得到一个interpolated(插值)分数,在计算过程中,已完成动画百分比会被加入到新的插值计算中。
过程三:
计算属性值当插值分数计算完成后,ValueAnimator会根据插值分数调用合适的 TypeEvaluator去计算运动中的属性值。 以上分析引入了两个概念:已完成动画分数(elapsed fraction)、插值分数( interpolated fraction )。
原理及特点:
1.属性动画:
插值器:作用是根据时间流逝的百分比来计算属性变化的百分比。
估值器:在1的基础上由这个东西来计算出属性到底变化了多少数值的类。
其实就是利用插值器和估值器,来计出各个时刻View的属性,然后通过改变View的属性来实现View的动画效果。
2.View动画:
只是影像变化,view的实际位置还在原来地方。
3.帧动画:
是在xml中定义好一系列图片之后,使用AnimatonDrawable来播放的动画。
它们的区别:
属性动画才是真正的实现了 view 的移动,补间动画对view 的移动更像是在不同地方绘制了一个影子,实际对象还是处于原来的地方。 当动画的 repeatCount 设置为无限循环时,如果在Activity退出时没有及时将动画停止,属性动画会导致Activity无法释放而导致内存泄漏,而补间动画却没问题。 xml 文件实现的补间动画,复用率极高。在 Activity切换,窗口弹出时等情景中有着很好的效果。 使用帧动画时需要注意,不要使用过多特别大的图,容导致内存不足。
为什么属性动画移动后仍可点击?
播放补间动画的时候,我们所看到的变化,都只是临时的。而属性动画呢,它所改变的东西,却会更新到这个View所对应的矩阵中,所以当ViewGroup分派事件的时候,会正确的将当前触摸坐标,转换成矩阵变化后的坐标,这就是为什么播放补间动画不会改变触摸区域的原因了。
2.5、Context相关
-
Activity和Service以及Application的Context是不一样的,Activity继承自ContextThemeWraper.其他的继承自Contextwrapper。
-
getApplication()用来获取Application实例的,但是这个方法只有在Activity和Service中才能调用的到。那也许在绝大多数情况下我们都是在Activity或者Servic中使用Application的,但是如果在一些其它的场景,比如broadcastReceiver中也想获得Application的实例,这时就可以借助getApplicationContext()方法,getApplicationContext()比getApplication()方法的作用域会更广一些,任何一个Context的实例,只要调用getApplicationContext()方法都可以拿到我们的Application对象。
-
创建对话框时不可以用Application的context,只能用Activity的context。
-
Context的数量等于Activity的个数 + Service的个数 +1,这个1为Application。
2.6、Android各版本新特性
Android5.0新特性
- MaterialDesign设计风格
- 支持64位ART虚拟机(5.0推出的ART虚拟机,在5.0之前都是Dalvik。他们的区别是: Dalvik,每次运行,字节码都需要通过即时编译器转换成机器码(JIT)。 ART,第一次安装应用的时候,字节码就会预先编译成机器码(AOT))
- 通知详情可以用户自己设计
Android6.0新特性
Android7.0新特性
Android8.0(O)新特性
- 优化通知
- 通知渠道 (Notification Channel) 通知标志 休眠 通知超时 通知设置 通知清除
- 画中画模式:清单中Activity设置android:supportsPictureInPicture
- 后台限制
- 自动填充框架
- 系统优化
Android9.0(P)新特性
- 室内WIFI定位
- “刘海”屏幕支持
- 安全增强
Android10.0(Q)新特性
Android11.0(R)新特性
2.7、Asset目录与res目录的区别?
res/anim:存放动画资源。
res/raw:和 asset 下文件一样,打包时直接打入程序安装包中(会映射到 R 文件中)。
2.8、Handler机制
Android消息循环流程图如下所示:
- message:消息。
- MessageQueue:消息队列,负责消息的存储与管理,负责管理由 Handler 发送过来的 Message。读取会自动删除消息,单链表维护,插入和删除上有优势。在其next()方法中会无限循环,不断判断是否有消息,有就返回这条消息并移除。
- Looper:消息循环器,负责关联线程以及消息的分发,在该线程下从 MessageQueue获取 Message,分发给Handler,Looper创建的时候会创建一个 MessageQueue,调用loop()方法的时候消息循环开始,其中会不断调用messageQueue的next()方法,当有消息就处理,否则阻塞在messageQueue的next()方法中。当Looper的quit()被调用的时候会调用messageQueue的quit(),此时next()会返回null,然后loop()方法也就跟着退出。
- Handler:消息处理器,负责发送并处理消息,面向开发者,提供 API,并隐藏背后实现的细节。
整个消息的循环流程还是比较清晰的,具体说来:
- Handler通过sendMessage()发送消息Message到消息队列MessageQueue。
- Looper通过loop()不断提取触发条件的Message,并将Message交给对应的target handler来处理。
- target handler调用自身的handleMessage()方法来处理Message。
事实上,在整个消息循环的流程中,并不只有Java层参与,很多重要的工作都是在C++层来完成的。我们来看下这些类的调用关系。
注:虚线表示关联关系,实线表示调用关系。
在这些类中MessageQueue是Java层与C++层维系的桥梁,MessageQueue与Looper相关功能都通过MessageQueue的Native方法来完成,而其他虚线连接的类只有关联关系,并没有直接调用的关系,它们发生关联的桥梁是MessageQueue。
总结
Handler 发送的消息由 MessageQueue 存储管理,并由 Looper 负责回调消息到 handleMessage()。
线程的转换由 Looper 完成,handleMessage() 所在线程由 Looper.loop() 调用者所在线程决定。
Handler 引起的内存泄露原因以及最佳解决方案
Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露。 这个泄露是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler 持有,这样最终就导致 Activity 泄露。
解决:将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并在Acitivity的onDestroy()中调用handler.removeCallbacksAndMessages(null)及时移除所有消息。
为什么我们能在主线程直接使用 Handler,而不需要创建 Looper ?
通常我们认为 ActivityThread 就是主线程。事实上它并不是一个线程,而是主线程操作的管理者。在 ActivityThread.main() 方法中调用了 Looper.prepareMainLooper() 方法创建了 主线程的 Looper ,并且调用了 loop() 方法,所以我们就可以直接使用 Handler 了。
因此我们可以利用 Callback 这个拦截机制来拦截 Handler 的消息。如大部分插件化框架中Hook ActivityThread.mH 的处理。
Handler 里藏着的 Callback 能干什么?
Handler.Callback 有优先处理消息的权利 ,当一条消息被 Callback 处理并拦截(返回 true),那么 Handler 的 handleMessage(msg) 方法就不会被调用了;如果 Callback 处理了消息,但是并没有拦截,那么就意味着一个消息可以同时被 Callback 以及 Handler 处理。
创建 Message 实例的最佳方式
为了节省开销,Android 给 Message 设计了回收机制,所以我们在使用的时候尽量复用 Message ,减少内存消耗:
子线程里弹 Toast 的正确姿势
本质上是因为 Toast 的实现依赖于 Handler,按子线程使用 Handler 的要求修改即可,同理的还有 Dialog。
妙用 Looper 机制
- 将 Runnable post 到主线程执行;
- 利用 Looper 判断当前线程是否是主线程。
主线程的死循环一直运行是不是特别消耗cpu资源呢?
并不是,这里就涉及到Linux pipe/epoll机制,简单说就是在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放cpu资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质是同步I/O,即读写是阻塞的。所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量cpu资源。
handler postDelay这个延迟是怎么实现的?
handler.postDelay并不是先等待一定的时间再放入到MessageQueue中,而是直接进入MessageQueue,以MessageQueue的时间顺序排列和唤醒的方式结合实现的。
2.9、OOM 是否可以try catch
只有在一种情况下,这样做是可行的:
但是这通常不是合适的做法。
Java中管理内存除了显式地catch OOM之外还有更多有效的方法:比如SoftReference, WeakReference, 硬盘缓存等。 在JVM用光内存之前,会多次触发GC,这些GC会降低程序运行的效率。 如果OOM的原因不是try语句中的对象(比如内存泄漏),那么在catch语句中会继续抛出OOM。
2.10、activty和Fragmengt之间怎么通信?Fragmengt和Fragmengt怎么通信?
2.11、服务启动一般有几种,服务和activty之间怎么通信,服务和服务之间怎么通信?
startService:
- onCreate()—>onStartCommand() —> onDestory()
- 如果服务已经开启,不会重复的执行onCreate(), 而是会调用onStartCommand()。一旦服务开启跟调用者(开启者)就没有任何关系了。 开启者退出了,开启者挂了,服务还在后台长期的运行。 开启者不能调用服务里面的方法。
bindService:
通信:
- 通过Binder对象。
- 通过broadcast(广播)。
2.12、广播注册一般有几种,各有什么优缺点?
第一种是常驻型(静态注册):当应用程序关闭后如果有信息广播来,程序也会被系统调用,自己运行。
第二种不常驻(动态注册):广播会跟随程序的生命周期。
动态注册
优点: 在android的广播机制中,动态注册优先级高于静态注册优先级,因此在必要情况下,是需要动态注册广播接收者的。
缺点: 当用来注册的 Activity 关掉后,广播也就失效了。
静态注册
优点: 无需担忧广播接收器是否被关闭,只要设备是开启状态,广播接收器就是打开着的。
缺点:广播一直存在,可能会对手机资源有消耗。
3.最后
篇幅有限,以上是关于Android基础面试的12个知识点,感兴趣的话,可以关注我的公众号,里面有4篇专门关于android面试基础的知识点,而且也会持续输出关于Android或Java知识点的文章。
期待你的关注!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。