Android面试题总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_20521573/article/details/82531089

Handler机制原理
https://blog.csdn.net/qq_20521573/article/details/77919141

Activity相关问题

1. Activity的生命周期
这里写图片描述
1)启动Activity:系统会先调用onCreate方法,这是生命周期第一个方法,然后调用onStart方法,最后调用onResume,Activity进入运行状态。
onCreate方法:一般做一些初始化工作,比如setContentView去加载布局资源,初始化Activity所需的数据。
onStart方法:表示Activity正在启动,已经可见,但是无法和用户交互。
onResume方法:Activity已经可见并且开始活动,已经出现在前台。
2)当前Activity被其他Activity覆盖其上或被锁屏:系统会调用onPause方法,暂停当前Activity的执行。
3)当前Activity由被覆盖状态回到前台或解锁屏:系统会调用onResume方法,再次进入运行状态。
4)当前Activity转到新的Activity界面或按Home键回到主屏,自身退居后台:系统会先调用onPause方法,然后调用onStop方法,进入停滞状态。
5)用户后退回到此Activity:系统会先调用onRestart方法,然后调用onStart方法,最后调用onResume方法,再次进入运行状态。
6)用户退出当前Activity:系统先调用onPause方法,然后调用onStop方法,最后调用onDestory方法,结束当前Activity

2. Acitivty的四种启动模式与特点
1)standard模式
特点:1.Activity的默认启动模式
2.每启动一个Activity就会在栈顶创建一个新的实例。例如:闹钟程序
缺点:当Activity已经位于栈顶时,而再次启动Activity时还需要在创建一个新的实例,不能直接复用。
2)singleTop模式
特点:该模式会判断要启动的Activity实例是否位于栈顶,如果位于栈顶直接复用,否则创建新的实例。 例如:浏览器的书签
缺点:如果Activity并未处于栈顶位置,则可能还会创建多个实例。
3)singleTask模式
特点:使Activity在整个应用程序中只有一个实例。每次启动Activity时系统首先检查栈中是否存在当前Activity实例,如果存在
则直接复用,并把当前Activity之上所有实例全部出栈。例如:浏览器主界面
4)singleInstance模式
特点:该模式的Activity会启动一个新的任务栈来管理Activity实例,并且该势力在整个系统中只有一个。无论从那个任务栈中 启动该Activity,都会是该Activity所在的任务栈转移到前台,从而使Activity显示。主要作用是为了在不同程序中共享一个Activity
3.Activity的启动过程(不要回答生命周期)
https://blog.csdn.net/luoshengyang/article/details/6689748

性能优化

1.Android中的内存泄漏

2.OOM
在实践操作当中,可以从四个方面着手减小内存使用,首先是减小对象的内存占用,其次是内存对象的重复利用,然后是避免对象的内存泄露,最后是内存使用策略优化。
1)减小对象的内存占用
使用更加轻量级的数据结构
例如,我们可以考虑使用ArrayMap/SparseArray而不是HashMap等传统数据结构,相比起Android系统专门为移动操作系统编写的ArrayMap容器,在大多数情况下,HashMap都显示效率低下,更占内存。另外,SparseArray更加高效在于,避免了对key与value的自动装箱,并且避免了装箱后的解箱。
避免使用Enum:
在Android中应该尽量使用int来代替Enum,因为使用Enum会导致编译后的dex文件大小增大,并且使用Enum时,其运行时还会产生额外的内存占用。
减小Bitmap对象的内存占用:
inBitmap:如果设置了这个字段,Bitmap在加载数据时可以复用这个字段所指向的bitmap的内存空间。但是,内存能够复用也是有条件的。比如,在Android 4.4(API level 19)之前,只有新旧两个Bitmap的尺寸一样才能复用内存空间。Android 4.4开始只要旧 Bitmap 的尺寸大于等于新的 Bitmap 就可以复用了。
inSampleSize:缩放比例,在把图片载入内存之前,我们需要先计算出一个合适的缩放比例,避免不必要的大图载入。
decode format:解码格式,选择ARGB_8888 RBG_565 ARGB_4444 ALPHA_8,存在很大差异。
ARGB_4444:每个像素占四位,即A=4,R=4,G=4,B=4,那么一个像素点占4+4+4+4=16位 ARGB_8888:每个像素占四位,即A=8,R=8,G=8,B=8,那么一个像素点占8+8+8+8=32位 RGB_565:每个像素占四位,即R=5,G=6,B=5,没有透明度,那么一个像素点占5+6+5=16位 ALPHA_8:每个像素占四位,只有透明度,没有颜色。
使用更小的图片:在设计给到资源图片的时候,我们需要特别留意这张图片是否存在可以压缩的空间,是否可以使用一张更小的图片。尽量使用更小的图片不仅仅可以减少内存的使用,还可以避免出现大量的InflationException。假设有一张很大的图片被XML文件直接引用,很有可能在初始化视图的时候就会因为内存不足而发生InflationException,这个问题的根本原因其实是发生了OOM。
2)内存对象的重复使用
大多数对象的复用,最终实施的方案都是利用对象池技术,要么是在编写代码的时候显式的在程序里面去创建对象池,然后处理好复用的实现逻辑,要么就是利用系统框架既有的某些复用特性达到减少对象的重复创建,从而减少内存的分配与回收。

复用系统自带资源:Android系统本身内置了很多的资源,例如字符串/颜色/图片/动画/样式以及简单布局等等,这些资源都可以在应用程序中直接引用。这样做不仅仅可以减少应用程序的自身负重,减小APK的大小,另外还可以一定程度上减少内存的开销,复用性更好。但是也有必要留意Android系统的版本差异性,对那些不同系统版本上表现存在很大差异,不符合需求的情况,还是需要应用程序自身内置进去。
ListView ViewHodler

Bitmap对象的复用:在ListView与GridView等显示大量图片的控件里面需要使用LRU的机制来缓存处理好的Bitmap。

inBitmap:使用inBitmap属性可以告知Bitmap解码器去尝试使用已经存在的内存区域,新解码的bitmap会尝试去使用之前那张bitmap在heap中所占据的pixel data内存区域,而不是去问内存重新申请一块区域来存放bitmap。

使用inBitmap,在4.4之前,只能重用相同大小的bitmap的内存区域,而4.4之后你可以重用任何bitmap的内存区域,只要这块内存比将要分配内存的bitmap大就可以。这里最好的方法就是使用LRUCache来缓存bitmap,后面来了新的bitmap,可以从cache中按照api版本找到最适合重用的bitmap,来重用它的内存区域。
新申请的bitmap与旧的bitmap必须有相同的解码格式
避免在onDraw方法里面执行对象的创建:类似onDraw等频繁调用的方法,一定需要注意避免在这里做创建对象的操作,因为他会迅速增加内存的使用,而且很容易引起频繁的gc,甚至是内存抖动。
StringBuilder:在有些时候,代码中会需要使用到大量的字符串拼接的操作,这种时候有必要考虑使用StringBuilder来替代频繁的“+”。
3)避免内存泄漏
内部类引用导致Activity的泄漏:最典型的场景是Handler导致的Activity泄漏,如果Handler中有延迟的任务或者是等待执行的任务队列过长,都有可能因为Handler继续执行而导致Activity发生泄漏。
Activity Context被传递到其他实例中,这可能导致自身被引用而发生泄漏。
考虑使用Application Context而不是Activity Context
注意临时Bitmap对象的及时回收
注意监听器的注销
注意缓存容器中的对象泄漏:不使用的对象要将引用置空。
注意Cursor对象是否及时关闭
4)内存优化策略
综合考虑设备内存阈值与其他因素设计合适的缓存大小
*onLowMemory():*Android系统提供了一些回调来通知当前应用的内存使用情况,通常来说,当所有的background应用都被kill掉的时候,forground应用会收到onLowMemory()的回调。在这种情况下,需要尽快释放当前应用的非必须的内存资源,从而确保系统能够继续稳定运行。
*onTrimMemory():*Android系统从4.0开始还提供了onTrimMemory()的回调,当系统内存达到某些条件的时候,所有正在运行的应用都会收到这个回调,同时在这个回调里面会传递以下的参数,代表不同的内存使用情况,收到onTrimMemory()回调的时候,需要根据传递的参数类型进行判断,合理的选择释放自身的一些内存占用,一方面可以提高系统的整体运行流畅度,另外也可以避免自己被系统判断为优先需要杀掉的应用
资源文件需要选择合适的文件夹进行存放:例如我们只在hdpi的目录下放置了一张100100的图片,那么根据换算关系,xxhdpi的手机去引用那张图片就会被拉伸到200200。需要注意到在这种情况下,内存占用是会显著提高的。对于不希望被拉伸的图片,需要放到assets或者nodpi的目录下。
谨慎使用static对象
优化布局层次,减少内存消耗
谨慎使用依赖注入框架
3.卡顿优化
导致Android界面滑动卡顿主要有两个原因:
UI线程(main)有耗时操作
视图渲染时间过长,导致卡顿
Android系统每隔16ms就会发送一个VSYNC信号(VSYNC:vertical synchronization 垂直同步,帧同步),触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的正常帧率:60fps。一旦这时候系统正在做大于16ms的耗时操作,系统就会无法响应VSYNC信号,执行渲染工作,导致发生丢帧现象。
用户容易在UI执行动画、ListView、RecyclerView滑动的时候感知到界面的卡顿与不流畅现象。所以开发者一定要注意在设计布局时不要嵌套太多层,多使用 include方法引入布局。同时不要让动画执行次数太多,导致CPU或者GPU负载过重。
界面卡顿的主要元凶—— 过度绘制
过渡绘制是指屏幕上某个像素在同一帧的时间内绘制了多次。在多层次的UI结构里面,如果不可见的UI也在做绘制操作,这就会导致某些像素区域被绘制了多次,这就是很大程度上浪费了CPU和GPU资源。最最常见的过度绘制,就是设置了无用的背景颜色!!!
对于Overdraw这个问题还是很容易发现的,我们可以通过以下步骤打开显示GPU过度绘制(Show GPU Overrdraw)选项

设置 -> 开发者选项 -> 调试GPU过度绘制 -> 显示GPU过度绘制

打开以后之后,你会发现屏幕上有各种颜色,此时你可以切换到需要检测的程序与界面,对于各个色块的含义,请看下图:
这里写图片描述
蓝色,淡绿,淡红,深红代表了4种不同程度的Overdraw情况,
蓝色: 意味着overdraw 1倍。像素绘制了两次。大片的蓝色还是可以接受的(若整个窗口是蓝色的,可以摆脱一层)。
绿色: 意味着overdraw 2倍。像素绘制了三次。中等大小的绿色区域是可以接受的但你应该尝试优化、减少它们。
淡红: 意味着overdraw 3倍。像素绘制了四次,小范围可以接受。
深红: 意味着overdraw 4倍。像素绘制了五次或者更多。这是错误的,要修复它们。
我们的目标就是尽量减少红色Overdraw,看到更多的蓝色区域。
解决问题的工具和方法
通过Hierarchy Viewer去检测渲染效率,去除不必要的嵌套
通过Show GPU Overdraw去检测Overdraw,最终可以通过移除不必要的背景。

4.ANR问题
ANR全称Application Not Responding,意思就是程序未响应。
1)出现场景
主线程被IO操作(从4.0之后网络IO不允许在主线程中)阻塞。
主线程中存在耗时的计算
主线程中错误的操作,比如Thread.wait或者Thread.sleep等
Android系统会监控程序的响应状况,一旦出现下面两种情况,则弹出ANR对话框
应用在5秒内未响应用户的输入事件(如按键或者触摸)
BroadcastReceiver未在10秒内完成相关的处理
2)如何避免
基本的思路就是将IO操作在工作线程来处理,减少其他耗时操作和错误操作
使用AsyncTask处理耗时IO操作。
使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同。
使用Handler处理工作线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程。
Activity的onCreate和onResume回调中尽量避免耗时的代码
BroadcastReceiver中onReceive代码也要尽量减少耗时,建议使用IntentService处理。
3)如何改善
通常100到200毫秒就会让人察觉程序反应慢,为了更加提升响应,可以使用下面的几种方法
如果程序正在后台处理用户的输入,建议使用让用户得知进度,比如使用ProgressBar控件。
程序启动时可以选择加上欢迎界面,避免让用户察觉卡顿。
使用Systrace和TraceView找出影响响应的问题。
如果开发机器上出现问题,我们可以通过查看/data/anr/traces.txt即可,最新的ANR信息在最开始部分。

View相关问题

1.事件分发机制
https://www.jianshu.com/p/e99b5e8bd67b
2.View绘制流程
https://www.jianshu.com/p/060b5f68da79
3.View的刷新机制
https://blog.csdn.net/chenzhiqin20/article/details/8628952

Service相关问题

1.Service的生命周期
这里写图片描述

这里写图片描述
2.Service的两种启动方式
1)生命周期上的区别
执行startService时,Service会经历onCreate->onStartCommand。当执行stopService时,直接调用onDestroy方法。调用者如果没有stopService,Service会一直在后台运行,下次调用者再起来仍然可以stopService。
执行bindService时,Service会经历onCreate->onBind。这个时候调用者和Service绑定在一起。调用者调用unbindService方法或者调用者Context不存在了(如Activity被finish了),Service就会调用onUnbind->onDestroy。这里所谓的绑定在一起就是说两者共存亡了。
多次调用startService,该Service只能被创建一次,即该Service的onCreate方法只会被调用一次。但是每次调用startService,onStartCommand方法都会被调用。Service的onStart方法在API 5时被废弃,替代它的是onStartCommand方法。
第一次执行bindService时,onCreate和onBind方法会被调用,但是多次执行bindService时,onCreate和onBind方法并不会被多次调用,即并不会多次创建服务和绑定服务。

猜你喜欢

转载自blog.csdn.net/qq_20521573/article/details/82531089