共计 20496 个字符,预计需要花费 52 分钟才能阅读完成。
缘起
有很多 Android 开发人员筹备面试,却不晓得如何筹备?于是纷纷上网发帖求助。
甚至很多人网上轻易找找面试题什么的,其后果就是[字节惨挂在三面],挥泪整顿面筋。等诸多文章火了,究其原因就是这些文章戳中了大部分面试者的痛点,面试被刷了。
想到还有很多 android 程序员没有找到 Android 面试纲要。不晓得如何筹备 Android 面试。
于是,我就想罗唆我本人做这个事吧,就算没人看,也当我本人的年终总结了。
如何筹备 android 面试
纯技术方面的筹备,如果是的话,我就提供一些高见,大部分算是一些开发常识死角或者 tips 吧,权当抛砖引玉了:)
明天就总结下 2020 年搜集整理的面试题,难度不大,大佬能够间接路过,当然发发善心点个赞也是能够的❤️。
Activity 面试题
1、Activity 是什么
Activity 是四大组件之一,它提供一个界面让用户点击和各种滑动操作,这就是 Activity
2、Activity 四种状态
- runing
- paused
- stopped
- killed
3、Activity 生命周期
- onCreate()
- onStart()
- onResume()
- onPause()
- onStop()
- onDestroy()
- onRestart()
4、Activity 切换横屏时生命周期
- onSaveInstanceState()
- onPause()
- onStop()
- onDestroy()
- onCreate()
- onStart()
- onRestoreInstanceState()
- onResume()
5、过程的优先级
oom_adj
是 linux 内核调配给每个零碎过程的一个值,代表过程的优先级,过程回收机制就是依据这个优先级来决定是否进行回收。过程的 oom_adj
越大,示意此过程优先级越低,越容易被杀回收;越小,示意过程优先级越高,越不容易被杀回收。一般 app 过程的 oom_adj
>=0,零碎过程的oom_adj
才可能小于 0。过程优先级从小到大如下
- 空过程
- 后盾过程
- 服务过程
- 可见过程
- 前台过程
6、Activity 工作栈
- 先进后出
7、Activity 启动模式
- standard
- singletop
- singletask
- singleinstance
8、scheme 跳转协定
android 中的 scheme 是一种页面内跳转协定,通过定义本人的 scheme 协定,能够跳转到 app 中的各个页面
- 服务器能够定制化通知 app 跳转哪个页面
- App 能够通过跳转到另一个 App 页面
- 能够通过 H5 页面跳转页面
9、Context、Activity、Application 之间有什么区别
Activity 和 Application 都是 Context 的子类。Context 从字面上了解就是上下文的意思,在理论利用中它也的确是起到了治理上下文环境中各个参数和变量的总用,不便咱们能够简略的拜访到各种资源。尽管 Activity 和 Application 都是 Context 的子类,然而他们保护的生命周期不一样。前者保护一个 Acitivity 的生命周期,所以其对应的 Context 也只能拜访该 activity 内的各种资源。后者则是保护一个 Application 的生命周期
10、Activity 启动过程
- 在装置利用的时候,零碎会启动 PackaManagerService 治理服务,这个治理服务会对 AndroidManifest 进行解析,从而失去应用程序中的相干信息,比方 service,activity,Broadcast 等等,而后取得相干组件的信息
- 当用户点击利用图标时,就会调用
startActivitySately()
,而这个办法外部则是调用startActivty()
,startActivity()
最终还是会调用startActivityForResult()
。因为startActivityForResult()
是有返回后果的,零碎间接返回 -1,示意不须要返回后果 startActivityForResult()
通过 Instrumentation 类中的execStartActivity()
来启动 activity,Instrumentation 这个类次要作用是监控程序和零碎之间的交互。在这个execStartActivity()
中会获取 ActivityManagerService 的代理对象,通过这个代理对象进行启动 activity- 在 ActivityManagerService 的代理对象中,通过 Binder 通信,调用到
ApplicationThread.scheduleLaunchActivity()
进行启动 activity,在这个办法中创立一个 ActivityClientRecord 对象,用来记录启动 Activity 组件的信息,而后通过 handler 将 ActivityClientRecord 发送进来 - 在 handler 收到音讯后,调用
ActivityThread.handleLaunchActivity()
启动 Activity
11、简述 Activity,View,Window 三者关系
- Activity 实质是上下文,View 实质是视图,Window 实质是窗口
- Activity 结构的时候会初始化一个 Window,其具体实现是 PhoneWindow
- PhoneWindow 中有一个 ViewRoot(View 或 ViewGroup),是最初始的根视图
- ViewRoot 通过 addView()将 View 增加到根视图上,实际上是将 View 交给了 PhoneWindow 解决
- View 的事件监听是由 WindowManagerService 来承受音讯,并且回调 Activity 函数
Fragment 面试题
1、Fragment 为什么被称为第五大组件
Fragment 比 Activity 更节俭内存,其切换模式也更加舒服,应用频率不低于四大组件,且有本人的生命周期,而且必须依附于 Activity
2、Activity 创立 Fragment 的形式
- 动态创立
- 动态创建
3、FragmentPageAdapter 和 FragmentPageStateAdapter 的区别
- FragmentPageAdapter 在每次切换页面的的时候,是将 Fragment 进行拆散,适宜页面较少的 Fragment 应用以保留一些内存,对系统内存不会多大影响
- FragmentPageStateAdapter 在每次切换页面的时候,是将 Fragment 进行回收,适宜页面较多的 Fragment 应用,这样就不会耗费更多的内存
4、Fragment 生命周期
- onAttach()
- onCreate()
- onCreateView()
- onActivityCreated()
- onStart()
- onResume()
- onPause()
- onStop()
- onDestroyView()
- onDestroy()
- onDetach()
5、Fragment 的通信
- Fragment 调用 Activity 中的办法:getActivity
- Activity 调用 Fragment 中的办法:接口回调
- Fragment 调用 Fragment 中的办法:FragmentManager.findFragmentById
6、Fragment 的 replace、add、remove 办法
- replace:代替 Fragment 的栈顶页面
- add:增加 Fragment 到栈顶页面
- remove:移除 Fragment 栈顶页面
Service 面试题
1、Service 是什么
Service 是四大组件之一,它能够在后盾执行长时间运行操作而没有用户界面的利用组件
2、Service 和 Thread 的区别
- Service 是安卓中零碎的组件,它运行在独立过程的主线程中,不能够执行耗时操作。Thread 是程序执行的最小单元,调配 CPU 的根本单位,能够开启子线程执行耗时操作
- Service 在不同 Activity 中能够获取本身实例,能够不便的对 Service 进行操作。Thread 在不同的 Activity 中难以获取本身实例,如果 Activity 被销毁,Thread 实例就很难再获取失去
3、Service 启动形式
- startService
- bindService
4、Service 生命周期
- startService
- onCreate()
- onStartCommand()
- onDestroy()
- bindService
- onCreate()
- onBind()
- onUnbind()
- onDestroy()
Broadcast Receiver 面试题
1、Broadcast Receiver 是什么
Broadcast 是四大组件之一,是一种宽泛使用在应用程序之间传输信息的机制,通过发送 Intent 来传送咱们的数据
2、Broadcast Receiver 的应用场景
- 同一 App 具备多个过程的不同组件之间的音讯通信
- 不同 App 之间的组件之间的音讯通信
3、Broadcast Receiver 的品种
- 一般播送
- 有序播送
- 本地播送
- Sticky 播送
4、Broadcast Receiver 的实现
- 动态注册:注册后始终运行,只管 Activity、过程、App 被杀死还是能够接管到播送
- 动静注册:追随 Activity 的生命周期
5、Broadcast Receiver 实现机制
- 自定义播送类继承 BroadcastReceiver,复写 onReceiver()
- 通过 Binder 机制向 AMS 进行注册播送
- 播送发送者通过 Binder 机制向 AMS 发送播送
- AMS 查找合乎相应条件的播送发送到 BroadcastReceiver 相应的循环队列中
- 音讯队列执行拿到播送,回调 BroadcastReceiver 的 onReceiver()
6、LocalBroadcastManager 特点
- 本地播送只能在本身 App 内流传,不用放心透露隐衷数据
- 本地播送不容许其余 App 对你的 App 发送该播送,不用放心安全漏洞被利用
- 本地播送比全局播送更高效
- 以上三点都是源于其外部是用 Handler 实现的
WebView 面试题
1、WebView 安全漏洞
- API16 之前存在近程代码执行安全漏洞,该破绽源于程序没有正确限度应用 WebView.addJavascriptInterface 办法,近程攻击者可通过应用 Java 反射机制利用该破绽执行任意 Java 对象的办法
2、WebView 销毁步骤
- WebView 在其余容器上时(如:LinearLayout),当销毁 Activity 时,须要在 onDestroy()中先移除容器上的 WebView,而后再将 WebView.destroy(),这样就不会导致内存透露
3、WebView 的 jsbridge
- 客户端和服务端之间能够通过 Javascript 来相互调用各自的办法
4、WebViewClient 的 onPageFinished
- WebViewClient 的 onPageFinished 在每次实现页面的时候调用,然而遇到未加载实现的页面跳转其余页面时,就会始终调用,应用 WebChromeClient.onProgressChanged 能够代替
5、WebView 后盾耗电
- 在 WebView 加载页面的时候,会主动开启线程去加载,如果不很好的敞开这些线程,就会导致电量耗费加大,能够采纳暴力的办法,间接在 onDestroy 办法中 System.exit(0)完结以后正在运行中的 java 虚拟机
6、WebView 硬件加速
Android3.0 引入硬件加速,默认会开启,WebView 在硬件加速的状况下滑动更加平滑,性能更加好,然而会呈现白块或者页面闪动的副作用,倡议 WebView 临时敞开硬件加速
7、WebView 内存透露
因为 WebView 是依附于 Activity 的,Activity 的生命周期和 WebView 启动的线程的生命周期是不统一的,这会导致 WebView 始终持有对这个 Activity 的援用而无奈开释,解决方案如下
- 独立过程,简略暴力,不过可能波及到过程间通信(举荐)
- 动静增加 WebView,对传入 WebView 中应用的 Context 应用弱援用
Binder 面试题
1、Linux 内核的基本知识
- 过程隔离 / 虚拟地址空间:过程间是不能够共享数据的,相当于被隔离,每个过程被调配到不同的虚拟地址中
- 零碎调用:Linux 内核对利用有拜访权限,用户只能在应用层通过零碎调用,调用内核的某些程序
- binder 驱动:它负责各个用户的过程,通过 binder 通信内核来进行交互的模块
2、为什么应用 Binder
- 性能上,相比传统的 Socket 更加高效
- 安全性高,反对协定单方相互校验
3、Binder 通信原理
- Service 端通过 Binder 驱动在 ServiceManager 的查找表中注册 Object 对象的 add 办法
- Client 端通过 Binder 驱动在 ServiceManager 的查找表中找到 Object 对象的 add 办法,并返回 proxy 对象的 add 办法,add 办法是个空实现,proxy 对象也不是真正的 Object 对象,是通过 Binder 驱动封装好的代理类的 add 办法
- 当 Client 端调用 add 办法时,Client 端会调用 proxy 对象的 add 办法,通过 Binder 驱动去申请 ServiceManager 来找到 Service 端真正对象,而后调用 Service 端的 add 办法
4、AIDL
- 客户端通过 aidl 文件的 Stub.asInterface()办法,拿到 Proxy 代理类
- 通过调用 Proxy 代理类的办法,将参数进行封包后,调用底层的 transact()办法
- transact()办法会回调 onTransact()办法,进行参数的解封
- 在 onTransact()办法中调用服务端对应的办法,并将后果返回
5、BpBinder 和 BBinder
BpBinder(客户端)对象和 BBinder(服务端)对象,它们都从 IBinder 类中派生而来,BpBinder(客户端)对象是 BBinder(服务端)对象的代理对象,关系图如下
- client 端:BpBinder.transact()来发送事务申请
- server 端:BBinder.onTransact()会接管到相应事务
Handler 面试题
1、Handler 是什么
Handler 通过发送和解决 Message 和 Runnable 对象来关联绝对应线程的 MessageQueue
2、Handler 应用办法
- post(runnable)
- sendMessage(message)
3、Handler 工作原理
- Android 进阶——Android 音讯机制之 Looper、Handler、MessageQueen
4、Handler 引起的内存透露
- 起因:非动态外部类持有外部类的匿名援用,导致 Activity 无奈开释
-
解决:
- Handler 外部持有内部 Activity 的弱援用
- Handler 改为动态外部类
- Handler.removeCallback()
AsyncTask 面试题
1、AsyncTask 是什么
它实质上就是一个封装了线程池和 Handler 的异步框架
2、AsyncTask 应用办法
-
三个参数
- Params:示意后台任务执行时的参数类型,该参数会传给 AysncTask 的 doInBackground()办法
- Progress:示意后台任务的执行进度的参数类型,该参数会作为 onProgressUpdate()办法的参数
- Result:示意后台任务的返回后果的参数类型,该参数会作为 onPostExecute()办法的参数
-
五个办法
- onPreExecute():异步工作开启之前回调,在主线程中执行
- doInBackground():执行异步工作,在线程池中执行
- onProgressUpdate():当 doInBackground 中调用 publishProgress 时回调,在主线程中执行
- onPostExecute():在异步工作执行之后回调,在主线程中执行
- onCancelled():在异步工作被勾销时回调
3、AsyncTask 工作原理
- Android 进阶——多线程系列之异步工作 AsyncTask 的应用与源码剖析
4、AsyncTask 引起的内存透露
- 起因:非动态外部类持有外部类的匿名援用,导致 Activity 无奈开释
-
解决:
- AsyncTask 外部持有内部 Activity 的弱援用
- AsyncTask 改为动态外部类
- AsyncTask.cancel()
5、AsyncTask 生命周期
在 Activity 销毁之前,勾销 AsyncTask 的运行,以此来保障程序的稳固
6、AsyncTask 后果失落
因为屏幕旋转、Activity 在内存缓和时被回收等状况下,Activity 会被从新创立,此时,旧的 AsyncTask 持有旧的 Activity 援用,这个时候会导致 AsyncTask 的 onPostExecute()对 UI 更新有效
7、AsyncTask 并行 or 串行
- AsyncTask 在 Android 2.3 之前默认采纳并行执行工作,AsyncTask 在 Android 2.3 之后默认采纳串行执行工作
- 如果须要在 Android 2.3 之后采纳并行执行工作,能够调用 AsyncTask 的 executeOnExecutor()
HandlerThread 面试题
1、HandlerThread 产生背景
当零碎有多个耗时工作须要执行时,每个工作都会开启一个新线程去执行耗时工作,这样会导致系统屡次创立和销毁线程,从而影响性能。为了解决这一问题,Google 提供了 HandlerThread,HandlerThread 是在线程中创立一个 Looper 循环器,让 Looper 轮询音讯队列,当有耗时工作进入队列时,则不须要开启新线程,在原有的线程中执行耗时工作即可,否则线程阻塞
2、HanlderThread 的特点、
- HandlerThread 实质上是一个线程,继承自 Thread
- HandlerThread 有本人的 Looper 对象,能够进行 Looper 循环,能够创立 Handler
- HandlerThread 能够在 Handler 的 handlerMessage 中执行异步办法
- HandlerThread 长处是异步不会梗塞,缩小对性能的耗费
- HandlerThread 毛病是不能同时持续进行多任务处理,须要期待进行解决,解决效率较低
- HandlerThread 与线程池不同,HandlerThread 是一个串行队列,背地只有一个线程
IntentService 面试题
1、IntentService 是什么
IntentService 是继承自 Service 并解决异步申请的一个类,其外部采纳 HandlerThread 和 Handler 实现的,在 IntentService 内有一个工作线程来解决耗时操作,其优先级比一般 Service 高。当工作实现后,IntentService 会主动进行,而不须要手动调用 stopSelf()。另外,能够屡次启动 IntentService,每个耗时操作都会以工作队列的形式在 IntentService 中 onHandlerIntent()回调办法中执行,并且每次只会执行一个工作线程
2、IntentService 应用办法
- 创立 Service 继承自 IntentService
- 覆写构造方法和 onHandlerIntent()办法
- 在 onHandlerIntent()中执行耗时操作
视图工作机制面试题
- Android 进阶——Android 视图工作机制之 measure、layout、draw
事件散发机制面试题
- Android 事件散发机制之 dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent
Android 我的项目构建面试题
1、Android 构建流程
[图片上传失败…(image-ccd96b-1606878198554)]
2、jenkins 继续集成构建
- 这里可参考蒲公英文档
3、git 常用命令
- git init:仓库的初始化
- git status:查看以后仓库的状态
- git diff:查看仓库与上次批改的内容
- git add:将文件放进暂存区
- git commit:提交代码
- git clone:克隆代码
- git bransh:查看以后分支
- git checkout:切换以后分支
4、git 工作流
-
fork/clone(支流)
- fork:将他人的仓库代码 fork 到本人的仓库上
- clone:克隆下本人仓库的代码
- update、commit:批改代码并提交到本人的仓库
- push:提交到本人的仓库
- pull request:申请增加到他人的仓库
- clone
5、proguard 是什么
ProGuard 工具是用于压缩、优化和混同咱们的代码,其主作用是移除或混同代码中无用类、字段、办法和属性
6、proguard 技术性能
- 压缩
- 优化
- 混同
- 预检测
7、proguard 工作原理
将无用的字段或办法存入到 EntryPoint 中,将非 EntryPoint 的字段和办法进行替换
8、为什么要混同
因为 Java 是一门跨平台的解释性语言,其源代码被编译成 class 字节码来适应其余平台,而 class 文件蕴含了 Java 源代码信息,很容易被反编译
9、annotationProcessor 与 compileOnly 的区别
annotationProcessor 与 compileOnly 都是只编译并不打入 apk 中
- annotationProcessor:编译时生成代码,编译完就不须要了
- compileOnly:有反复的库时,能够剃除反复库,只保留一个库
ANR 面试题
1、什么是 ANR
Application Not Responding,页面无响应的对话框
2、产生 ANR 的条件
应用程序的响应性是由 ActivityManager 和 WindowManager 零碎服务监督的,当 ANR 产生条件满足时,就会弹出 ANR 的对话框
- Activity 超过 5 秒无响应
- BroadcastReceiver 超过 10 秒无响应
- Service 超过 20 秒无响应
3、造成 ANR 的次要起因
主线程被 IO 操作阻塞
- Activity 的所有生命周期回调都是执行在主线程的
- Service 默认执行在主线程中
- BoardcastReceiver 的回调 onReceive()执行在主线程中
- AsyncTask 的回调除了 doInBackground,其余都是在主线程中
- 没有应用子线程 Looper 的 Handler 的 handlerMessage,post(Runnable)都是执行在主线程中
4、如何解决 ANR
- 应用 AsyncTask 解决耗时 IO 操作
- 应用 Thread 或 HandlerThread 进步优先级
- 应用 Handler 解决工作线程的耗时操作
- Activity 的 onCreate 和 onResume 回调尽量避免耗时操作
OOM 面试题
1、什么是 OOM
OOM 指 Out of memory(内存溢出),以后占用内存加上咱们申请的内存资源超过了 Dalvik 虚拟机的最大内存限度就会抛出 Out of memory 异样
2、OOM 相干概念
- 内存溢出:指程序在申请内存时,没有足够的空间供其应用
- 内存透露:指程序调配进来的内存不再应用,无奈进行回收
- 内存抖动:指程序短时间内大量创建对象,而后回收的景象
3、解决 OOM
Bitmap 相干
- 图片压缩
- 加载缩略图
- 在滚动时不加载图片
- 回收 Bitmap
- 应用 inBitmap 属性
- 捕捉异样
其余相干
- listview 重用 convertView、应用 lru
- 防止 onDraw 办法执行对象的创立
- 审慎应用多过程
Bitmap 面试题
1、recycle
- 在安卓 3.0 以前 Bitmap 是寄存在堆中的,咱们只有回收堆内存即可
- 在安卓 3.0 当前 Bitmap 是寄存在内存中的,咱们须要回收 native 层和 Java 层的内存
- 官网倡议咱们 3.0 当前应用 recycle 办法进行回收,该办法也能够不被动调用,因为垃圾回收器会主动收集不可用的 Bitmap 对象进行回收
- recycle 办法会判断 Bitmap 在不可用的状况下,将发送指令到垃圾回收器,让其回收 native 层和 Java 层的内存,则 Bitmap 进入 dead 状态
- recycle 办法是不可逆的,如果再次调用 getPixels()等办法,则获取不到想要的后果
2、LruCache 原理
LruCache 是个泛型类,外部采纳 LinkedHashMap 来实现缓存机制,它提供 get 办法和 put 办法来获取缓存和增加缓存,其最重要的办法 trimToSize 是用来移除起码应用的缓存和应用最久的缓存,并增加最新的缓存到队列中
3、计算采样率
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {if (width > height) {inSampleSize = Math.round((float)height / (float)reqHeight);
} else {inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
4、采样率压缩(缩略图)
public static Bitmap thumbnail(String path,int maxWidth, int maxHeight) {BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
options.inJustDecodeBounds = false;
int sampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
options.inSampleSize = sampleSize;
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inPurgeable = true;
options.inInputShareable = true;
if (bitmap != null && !bitmap.isRecycled()) {bitmap.recycle();
}
bitmap = BitmapFactory.decodeFile(path, options);
return bitmap;
}
5、品质压缩
public static String save(Bitmap bitmap,Bitmap.CompressFormat format, int quality, File destFile) {
try {FileOutputStream out = new FileOutputStream(destFile);
if (bitmap.compress(format, quality, out)) {out.flush();
out.close();}
if (bitmap != null && !bitmap.isRecycled()) {bitmap.recycle();
}
return destFile.getAbsolutePath();} catch (FileNotFoundException e) {e.printStackTrace();
} catch (IOException e) {e.printStackTrace();
}
return null;
}
6、尺寸压缩
public static void reSize(Bitmap bmp,File file,int ratio){Bitmap result = Bitmap.createBitmap(bmp.getWidth()/ratio, bmp.getHeight()/ratio,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
RectF rect = new RectF(0, 0, bmp.getWidth()/ratio, bmp.getHeight()/ratio);
canvas.drawBitmap(bmp, null, rect , null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
result.compress(Bitmap.CompressFormat.JPEG, 100, baos);
try {FileOutputStream fos = new FileOutputStream(file);
fos.write(baos.toByteArray());
fos.flush();
fos.close();} catch (Exception e) {e.printStackTrace();
}
}
7、保留到 SD 卡
public static String save(Bitmap bitmap,Bitmap.CompressFormat format, int quality, Context context) {if (!Environment.getExternalStorageState()
.equals(Environment.MEDIA_MOUNTED)) {return null;}
File dir = new File(Environment.getExternalStorageDirectory()
+ "/" + context.getPackageName() + "/save/");
if (!dir.exists()) {dir.mkdirs();
}
File destFile = new File(dir, UUID.randomUUID().toString());
return save(bitmap, format, quality, destFile);
}
8、三级缓存
- 网络缓存
- 本地缓存
- 内存缓存
9、NDK 压缩
Android 进阶——图片优化之品质压缩、尺寸压缩、采样率压缩、LibJpeg 压缩
10、webp 压缩
Android Webp 齐全解析 快来放大 apk 的大小吧 - 鸿洋的博客
UI 卡顿面试题
1、UI 卡顿原理
View 的绘制帧数放弃 60fps 是最佳,这要求每帧的绘制工夫不超过 16ms(1000/60),如果安卓不能在 16ms 内实现界面的渲染,那么就会呈现卡顿景象
2、UI 卡顿的起因剖析
- 在 UI 线程中做轻微的耗时操作,导致 UI 线程卡顿
- 布局 Layout 过于简单,无奈在 16ms 内实现渲染
- 同一时间动画执行的次数过多,导致 CPU 和 GPU 负载过重
- overDraw,导致像素在同一帧的工夫内被绘制屡次,使 CPU 和 GPU 负载过重
- View 频繁的触发 measure、layout,导致 measure、layout 累计耗时过多和整个 View 频繁的从新渲染
- 频繁的触发 GC 操作导致线程暂停,会使得安卓零碎在 16ms 内无奈实现绘制
- 冗余资源及逻辑等导致加载和执行迟缓
- ANR
3、UI 卡顿的优化
-
布局优化
- 应用 include、ViewStub、merge
- 不要呈现过于嵌套和冗余的布局
- 应用自定义 View 取代简单的 View
-
ListView 优化
- 复用 convertView
- 滑动不加载
-
背景和图片优化
- 缩略图
- 图片压缩
-
防止 ANR
- 不要在 UI 线程中做耗时操作
内存透露面试题
1、Java 内存透露引起的次要起因
长生命周期的对象持有短生命周期对象的援用就很可能产生内存透露
2、Java 内存调配策略
- 动态存储区:又称办法区,次要存储全局变量和动态变量,在整个程序运行期间都存在
- 栈区:办法体的局部变量会在栈区创立空间,并在办法执行完结后会主动开释变量的空间和内存
- 堆区:保留动静产生的数据,如:new 进去的对象和数组,在不应用的时候由 Java 回收器主动回收
3、Android 解决内存透露的例子
- 单例造成的内存透露:在单例中,应用 context.getApplicationContext()作为单例的 context
- 匿名外部类造成的内存透露:因为非动态外部类持有匿名外部类的援用,必须将外部类设置为 static
- Handler 造成的内存透露:应用 static 的 Handler 外部类,同时在实现外部类中持有 Context 的弱援用
- 防止应用 static 变量:因为 static 变量会跟 Activity 生命周期统一,当 Activity 退出后盾被后盾回收时,static 变量是不平安,所以也要治理好 static 变量的生命周期
- 资源未敞开造成的内存透露:比方 Socket、Broadcast、Cursor、Bitmap、ListView 等,应用完后要敞开
- AsyncTask 造成的内存透露:因为非动态外部类持有匿名外部类的援用而造成内存透露,能够通过 AsyncTask 外部持有内部 Activity 的弱援用同时改为动态外部类或在 onDestroy()中执行 AsyncTask.cancel()进行修复
内存治理面试题
1、Android 内存管理机制
- 分配机制
- 管理机制
2、内存管理机制的特点
- 更少的占用内存
- 在适合的时候,正当的开释系统资源
- 在零碎内存缓和的时候,能开释掉大部分不重要的资源
- 能正当的在非凡生命周期中,保留或还原重要数据
3、内存优化办法
- Service 实现工作后应进行它,或用 IntentService(因为能够主动进行服务)代替 Service
- 在 UI 不可见的时候,开释其 UI 资源
- 在零碎内存缓和的时候,尽可能多的开释非重要资源
- 防止滥用 Bitmap 导致内存节约
- 防止应用依赖注入框架
- 应用针对内存优化过的数据容器
- 应用 ZIP 对齐的 APK
- 应用多过程
冷启动和热启动面试题
1、什么是冷启动和热启动
- 冷启动:在启动利用前,零碎中没有该利用的任何过程信息
- 热启动:在启动利用时,在已有的过程上启动利用(用户应用返回键退出利用,而后马上又重新启动利用)
2、冷启动和热启动的区别
- 冷启动:创立 Application 后再创立和初始化 MainActivity
- 热启动:创立和初始化 MainActivity 即可
3、冷启动工夫的计算
这个工夫值从利用启动(创立过程)开始计算,到实现视图的第一次绘制为止
4、冷启动流程
- Zygote 过程中 fork 创立出一个新的过程
- 创立和初始化 Application 类、创立 MainActivity
- inflate 布局、当 onCreate/onStart/onResume 办法都走完
- contentView 的 measure/layout/draw 显示在界面上
总结:点击 App->IPC->Process.start->ActivityThread->Application 生命周期 ->Activity 生命周期 ->ViewRootImpl 测量布局绘制显示在界面上
5、冷启动优化
- 缩小第一个界面 onCreate()办法的工作量
- 不要让 Application 参加业务的操作
- 不要在 Application 进行耗时操作
- 不要以动态变量的形式在 Application 中保留数据
- 缩小布局的复杂性和深度
- 不要在 mainThread 中加载资源
- 通过懒加载形式初始化第三方 SDK
6、adb 命令获取启动工夫
adb shell am start -W packagename/MainActivity
- ThisTime: 最初一个 Activity 启动耗时
- TotalTime: 所有 Activity 启动耗时
- WaitTime:AMS 启动 Activity 的总耗时
其余优化面试题
1、Android 不必动态变量存储数据
- 动态变量等数据因为过程曾经被杀死而被初始化
- 应用其余数据传输方式:文件 /sp/contentProvider
2、SharePreference 平安问题
- 不能跨进程同步
- 文件不宜过大
3、内存对象序列化
- Serializeble:是 java 的序列化形式,Serializeble 在序列化的时候会产生大量的长期对象,从而引起频繁的 GC
- Parcelable:是 Android 的序列化形式,且性能比 Serializeble 高,Parcelable 不能应用在要将数据存储在硬盘上的状况
4、防止在 UI 线程中做沉重的操作
架构模式面试题
- Android 根底——框架模式 MVC 在安卓中的实际
- Android 根底——框架模式 MVP 在安卓中的实际
- Android 根底——框架模式 MVVM 之 DataBinding 的实际
插件化面试题
1、插件化解决的问题
- 动静加载 APK(反射、类加载器)
- 资源加载(反射、AssetManager、独立资源、分段资源)
- 代码加载(反射获取生命周期)
2、类加载器(Java 中字节码增加到虚拟机中)
- DexClassLoader:可能加载未装置的 jar/apk/dex,次要用于动静加载和代码热更新
- PathClassLoader:加载 /data/app 目录下的 apk 文件,只有用来加载零碎中曾经装置过的 apk
热更新面试题
1、热更新次要流程
- 线上查看到 Crash
- 拉出 Bugfix 分支修复 Crash 问题
- jenkins 构建和补丁生成
- app 通过推送或被动拉取补丁文件
- 将 Bugfix 代码合到 master 上
2、热更新支流框架
- Dexposed
- AndFix
- Nuwa
3、热更新的原理
- 在 ClassLoader 创立一个 dexElements 数组
- 将修复好的 dex 文件寄存在 dexElements 数组的最后面
- ClassLoader 会遍历 dexElements 数组,找到最后面的 dex 文件优先加载
过程保活面试题
1、过程的优先级
- 空过程
- 后盾过程
- 服务过程
- 可见过程
- 前台过程
2、Android 过程回收策略
- Low memory Killer(定时执行):通过一些比较复杂的评分机制,对过程进行打分,而后将分数高的过程断定为 bad 过程,杀死并开释内存
- OOM_ODJ:判断过程的优先级
3、Android 保活计划
- 利用零碎播送拉活
- 利用零碎 Service 机制拉活
- 利用 Native 过程拉活
- 利用 JobScheduler 机制拉活
- 利用账号同步机制拉活
Lint 面试题
1、什么是 Android Lint
Android Lint 是一个动态代码剖析工具,它可能对你的 Android 我的项目中潜在的 Bug、可优化的代码、安全性、性能、可用性、可拜访性、国际化等进行查看
2、Lint 工作流程
[图片上传失败…(image-d5f5ab-1606878198551)]
3、配置 Lint
- 创立 Lint.xml 到根目录下,自定义 Lint 安全等级等
- 在 Java 文件中能够应用 @suppressLint(“NewApi”)来漠视 Lint 的报错
- 在 xml 文件中能够应用 tool:ignore(“UnusedResources”)来漠视 Lint 的报错
- 自定义 Lint 查看,能够创立类,继承 Detector 和实现 JavaPsiScanner
Kotlin 面试题
1、什么是 Kotlin
- Kotlin 是一种基于 JVM 的编程语言
- 对 Java 的一种拓展,比 Java 更简洁
- Kotlin 反对函数式编程
- Kotlin 类和 Java 类能够互相调用
2、Kotlin 环境搭建
- 间接在 Plugin 中下载 Kotlin 插件即可
- 零碎会主动配置到 Kotlin 环境
虚拟机面试题
1、Dalvik 与 JIT
Dalvik 是 Android 虚拟机,JIT 则是 Dalvik 采纳的技术策略
在编译打包 APK 文件时,会通过以下流程Java->Class->Dalvik 字节码(dex)-> 每次执行代码都要编译成机器码 -> 交给底层解决
,这样解决起来效率低下,通过引入 JIT(即时编译技术),当 App 运行时,每当遇到一个新类,JIT 编译器就会对这个类进行即时编译,通过编译后的代码,会被优化成相当精简的原生型指令码,这样在下次执行到雷同逻辑的时候,速度就会更快。但因为每次启动 App 都须要即时编译,导致运行时耗电量大
2、ART 与 AOT
ART 是 Android 虚拟机,AOT 则是 ART 采纳的技术策略
在 ART 环境中,利用在第一次装置的时候,字节码就会事后编译成机器码,使其成为真正的本地利用,这一技术称为 AOT。之后关上 App 的时候,不须要额定的翻译工作,间接应用本地机器码运行,因而运行速度进步。但因为会事后编译,安装时间难免会缩短,而且会耗费更多的存储空间,但消耗掉空间的增幅通常不会超过利用代码包大小的 20%
3、发展史
- 2.2 ~ 4.4:Dalvik 虚拟机应用 JIT 技术
- 4.4 ~ 5.0:Dalvik 虚拟机和 ART 虚拟机共存
- 5.0 ~ x.0:ART 虚拟机应用 AOT 技术代替 Dalvik 虚拟机
4、JVM 与 Dalvik 不同
- 类加载零碎区别比拟大
- JVM 是基于栈,Dalvik 是基于寄存器
- JVM 执行的是 java 字节码文件,Dalvik 执行的是 dex 字节码文件
- Dalvik 能够同时存在多个,即便一个退出了也不会影响其余程序
5、Dalvik 与 ART 不同
- Dalvik 应用 JIT(Just In Time 运行时编译)来将字节码转换成机器码,效率低
- ART 采纳 AOT(Ahead Of Time 运行前编译或装置时编译)预编译技术,利用运行速度更快
- ART 会占用更多的利用安装时间和存储空间
注解面试题
1、什么是 Annotation
Java 提供的一种元程序中的元素关联任何信息和任何元数据(metadata)的路径和办法
2、什么是 metadata
- 元数据以标签的模式存在于 Java 代码中
- 元数据形容的信息是类型平安的
- 元数据须要编译器之外的工具额定的解决用来生成其余的程序部件
- 元数据能够只存在于 Java 源代码级别,也能够存在于编译之后的 Class 文件外部
3、注解分类
-
零碎内置规范注解
- @Override:示意重写
- @Deprecated:示意已过期
- @SuppressWarnnings:示意克制正告
-
元注解
- @Target:示意注解的润饰范畴
- @Retention:示意注解的代码生存期
- @Documented:示意注解为程序员的 API
- @Inherited:示意注解能够继承
-
@Target
- ElementType.CONSTRUCTOR: 结构器申明
- ElementType.FIELD: 成员变量、对象、属性(包含 enum 实例)
- ElementType.LOCAL_VARIABLE: 局部变量申明
- ElementType.METHOD: 办法申明
- ElementType.PACKAGE: 包申明
- ElementType.PARAMETER: 参数申明
- ElementType.TYPE: 类、接口(包含注解类型)或 enum 申明
-
@Retention
- RetentionPolicy.SOURCE: 在源文件中无效,当 Java 文件编译成 class 文件的时候,注解被遗弃
- RetentionPolicy.CLASS: 在 class 文件中无效,当 jvm 加载 class 文件时候被遗弃
- RetentionPolicy.RUNTIME: 在运行时无效,当 jvm 加载 class 文件之后,依然存在
-
生命周期
- RUNTIME > CLASS > SOURCE
- .java 文件 –> .class 文件 –> 内存中的字节码
4、注解申明
注解反对填写数组,同时反对多种范畴
@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ModuleWrapper {}
5、Android Support Annotation
- Nullness 注解(@NonNull、@Nullable):示意指定的空类型或非空类型
- ResourceType 注解(@StringRes、@IntegerRes、@ColorRes 等):示意指定的变量类型
- Threading 注解(@WorkerThread、@UIThread、@MainThread 等):示意指定的线程类型
- Range 注解(@IntRange、@FloatRange 等):示意容许传值的范畴
- OverridingMethods 注解(@CallSuper 等):示意调用父类的办法
6、注解的用处
- 束缚类
- 束缚变量
- 束缚入参
- 束缚返回值
网络面试题
1. 网页中输出 url,到渲染整个界面的整个过程,以及两头用了什么协定?
1)过程剖析:次要分为三步
DNS 解析
。用户输出 url 后,须要通过 DNS 解析找到域名对应的 ip 地址,有了 ip 地址能力找到服务器端。首先会查找浏览器缓存,是否有对应的 dns 记录。再持续依照操作系统缓存—路由缓存—isp 的 dns 服务器—根服务器的程序进行 DNS 解析,直到找到对应的 ip 地址。客户端(浏览器)和服务器交互
。浏览器依据解析到的 ip 地址和端口号发动 HTTP 申请,申请达到传输层,这里也就是 TCP 层,开始三次握手建设连贯。服务器收到申请后,发送相应报文给客户端(浏览器),客户端收到相应报文并进行解析,失去 html 页面数据,包含 html,js,css 等。客户端(浏览器)解析 html 数据
,构建 DOM 树,再结构出现树(render 树),最终绘制到浏览器页面上。
2)其中波及到 TCP/IP 协定簇,包含 DNS,TCP,IP,HTTP 协定等等。
2. 具体介绍下 TCP/IP
TCP/IP 个别指的是 TCP/IP 协定簇,次要包含了多个不同网络间实现信息传输波及到的各种协定
次要包含以下几层:
应用层
:次要提供数据和服务。比方 HTTP,FTP,DNS 等传输层
:负责数据的组装,分块。比方 TCP,UDP 等网络层
:负责通知通信的目的地,比方 IP 等数据链路层
:负责连贯网络的硬件局部,比方以太网,WIFI 等
3.TCP 的三次握手和四次挥手,为什么不是两次握手?为什么挥手多一次呢?
客户端简称 A,服务器端简称 B
1)TCP 建设连贯须要三次握手
- A 向 B 示意想跟 B 进行连贯(A 发送
syn
包,A 进入SYN_SENT
状态) - B 收到音讯,示意我也筹备好和你连贯了(B 收到
syn
包,须要确认syn
包,并且本人也发送一个syn
包,即发送了syn+ack
包,B 进入SYN_RECV
状态) - A 收到音讯,并通知 B 示意我收到你也筹备连贯的信号了(A 收到
syn+ack
包,向服务器发送确认包ack
,AB 进入established
状态)开始连贯。
2)TCP 断开连接须要四次挥手
- A 向 B 示意想跟 B 断开连接(A 发送
fin
,进入FIN_WAIT_1
状态) - B 收到音讯,然而 B 音讯没发送完,只能通知 A 我收到你的断开连接音讯(B 收到 fin,发送 ack,进入
CLOSE_WAIT
状态) - 过一会,B 数据发送结束,通知 A,我能够跟你断开了(B 发送 fin,进入
LAST_ACK
状态) - A 收到音讯,通知 B,能够他断开(A 收到 fin,发送 ack,B 进入
close
d 状态)
3)为什么挥手多一次
其实失常的断开和连贯都是须要 四次
:
- A 发消息给 B
- B 反馈给 A 示意正确收到音讯
- B 发送音讯给 A
- A 反馈给 B 示意正确收到音讯。
然而连贯中,第二步和第三步是 能够合并
的,因为连贯之前 A 和 B 是无分割的,所以没有其余状况须要解决。而断开的话,因为之前两端是失常连贯状态,所以第二步的时候不能保障 B 之前的音讯曾经发送结束,所以不能马上通知 A 要断开的音讯。这就是连贯为什么能够少一步的起因。
4)为什么连贯须要三次,而不是两次。
失常来说,我给你发消息,你通知我能收到,不就代表咱们之前通信是失常的吗?
- 简略答复就是,
TCP 是双向通信协定
,如果两次握手,不能保障 B 发给 A 的音讯正确达到。
TCP 协定为了实现牢靠传输,通信单方须要判断本人曾经发送的数据包是否都被接管方收到,如果没收到,就须要重发。
TCP 是怎么保障牢靠传输的?
序列号和确认号
。比方连贯的一方发送一段 80byte 数据,会带上一个序列号,比方 101。接管方收到数据,回复确认号 181(180+1),这样下一次发送音讯就会从 181 开始发送了。
所以握手过程中,比方 A 发送 syn 信号给 B,初始序列号为 120,那么 B 收到音讯,回复 ack
音讯,序列号为 120+1。同时 B 发送 syn
信号给 A,初始序列号为 256,如果收不到 A 的回复音讯,就会重发,否则失落这个序列号,就无奈失常实现前面的通信了。
这就是三次握手的起因。
4.TCP 和 UDP 的区别?
TCP
提供的是面向连贯,牢靠的字节流服务。即客户和服务器替换数据前,必须当初单方之间建设一个 TCP 连贯(三次握手),之后能力传输数据。并且提供超时重发,抛弃反复数据,测验数据,流量管制等性能,保证数据能从一端传到另一端。
UDP
是一个简略的面向数据报的运输层协定。它不提供可靠性,只是把应用程序传给 IP 层的数据报发送进来,然而不能保障它们能达到目的地。因为 UDP
在传输数据报前不必再客户和服务器之间建设一个连贯,且没有超时重发等机制,所以传输速度很快。
所以总结下来就是:
- TCP 是面向连贯的,UDP 是面向无连贯的
- TCP 数据报头包含序列号,确认号,等等。相比之下 UDP 程序结构较简略。
- TCP 是面向字节流的,UDP 是基于数据报的
- TCP 保证数据正确性,UDP 可能丢包
- TCP 保证数据程序,UDP 不保障
能够看到 TCP
实用于稳固的利用场景,他会保证数据的正确性和程序,所以个别的浏览网页,接口拜访都应用的是 TCP
传输,所以才会有 三次握手
保障连贯的稳定性。
而 UDP 是一种构造简略的协定,不会思考丢包啊,建设连贯等。长处在于数据传输很快,所以实用于直播,游戏等场景。
5.HTTP 的几种申请办法具体介绍
常见的有四种:
GET
获取资源,没有 body,幂等性POST
减少或者批改资源,有 bodyPUT
批改资源,有 body,幂等性DELETE
删除资源,幂等性
6.HTTP 申请和响应报文的格局,以及罕用状态码
1)申请报文:
// 申请行(包含 method、path、HTTP 版本)GET /s HTTP/1.1
//Headers
Host: www.baidu.com
Content-Type: text/plain
//Body
搜寻 ****
2)响应报文
// 状态行(包含 HTTP 版本、状态码,状态信息)HTTP/1.1 200 OK
//Headers
Content-Type: application/json; charset=utf-8
//Body
[{"info":"xixi"}]
3)罕用状态码
次要分为五种类型:
1 结尾
,代表临时性音讯,比方 100(持续发送)2 结尾
,代表申请胜利,比方 200(OK)3 结尾
,代表重定向,比方 304(内容无扭转)4 结尾
,代表客户端的一些谬误,比方 403(禁止拜访)5 结尾
,代表服务器的一些谬误,比方 500
出于篇幅的考量,本文不可能对 Android 面试纲要所有面试模块作出阐明。即便如此,沿着本文提供的思路,参考相干章节内容,剖析相干知识点和源码,你会很快、很容易地拿到一线互联网企业的 offer。
文档支付形式:点赞 + 关注,而后私信关键词【1】即可取得收费支付形式!