android移动应用开发,面试官都被搞懵了

### 一.Android中高级面试题 #### 1、Activity生命周期? `onCreate()` -> `onStart()` -> `onResume()` -> `onPause()` -> `onStop()` -> `onDetroy()` #### 2、Service生命周期? service 启动方式有两种,一种是通过`startService()`方式进行启动,另一种是通过`bindService()`方式进行启动。不同的启动方式他们的生命周期是不一样. 通过`startService()`这种方式启动的service,生命周期是这样:调用`startService()` --> `onCreate()`--> `onStartConmon()`--> `onDestroy()`。这种方式启动的话,需要注意一下几个问题, 第一:当我们通过`startService`被调用以后,多次在调用`startService()`,`onCreate()`方法也只会被调用一次,而`onStartConmon()`会被多次调用当我们调用`stopService()`的时候,`onDestroy()`就会被调用,从而销毁服务。 第二:当我们通过`startService`启动时候,通过intent传值,在`onStartConmon()`方法中获取值的时候,一定要先判断intent是否为null。 通过`bindService()`方式进行绑定,这种方式绑定service,生命周期走法:`bindService`-->`onCreate()`-->`onBind()`-->`unBind()`-->`onDestroy()`?` bingservice` 这种方式进行启动service好处是更加便利activity中操作service,比如加入service中有几个方法,a,b ,如果要在activity中调用,在需要在activity获取`ServiceConnection`对象,通过`ServiceConnection`来获取service中内部类的类对象,然后通过这个类对象就可以调用类中的方法,当然这个类需要继承Binder对象 #### 3、Activity的启动过程(不要回答生命周期) app启动的过程有两种情况,第一种是从桌面launcher上点击相应的应用图标,第二种是在activity中通过调用`startActivity`来启动一个新的activity。 我们创建一个新的项目,默认的根activity都是`MainActivity`,而所有的activity都是保存在堆栈中的,我们启动一个新的activity就会放在上一个activity上面,而我们从桌面点击应用图标的时候,由于launcher本身也是一个应用,当我们点击图标的时候,系统就会调用`startActivitySately()`,一般情况下,我们所启动的activity的相关信息都会保存在intent中,比如action,category等等。我们在安装这个应用的时候,系统也会启动一个`PackaManagerService`的管理服务,这个管理服务会对`AndroidManifest.xml`文件进行解析,从而得到应用程序中的相关信息,比如service,activity,Broadcast等等,然后获得相关组件的信息。 当我们点击应用图标的时候,就会调用`startActivitySately()`方法,而这个方法内部则是调用`startActivty()`,而`startActivity()`方法最终还是会调用`startActivityForResult()`这个方法。而在`startActivityForResult()`这个方法。因为`startActivityForResult()`方法是有返回结果的,所以系统就直接给一个-1,就表示不需要结果返回了。 而`startActivityForResult()`这个方法实际是通过Instrumentation类中的`execStartActivity()`方法来启动activity,Instrumentation这个类主要作用就是监控程序和系统之间的交互。而在这个`execStartActivity()`方法中会获取`ActivityManagerService`的代理对象,通过这个代理对象进行启动activity。启动会就会调用一个`checkStartActivityResult()`方法,如果说没有在配置清单中配置有这个组件,就会在这个方法中抛出异常了。当然最后是调用的是`Application.scheduleLaunchActivity()`进行启动activity,而这个方法中通过获取得到一个`ActivityClientRecord`对象,而这个`ActivityClientRecord`通过handler来进行消息的发送,系统内部会将每一个activity组件使用`ActivityClientRecord`对象来进行描述,而`ActivityClientRecord`对象中保存有一个`LoaderApk`对象,通过这个对象调用`handleLaunchActivity`来启动activity组件,而页面的生命周期方法也就是在这个方法中进行调用。 #### 4、Broadcast注册方式与区别? #### 5、HttpClient与HttpUrlConnection的区别? **此处延伸**:Volley里用的哪种请求方式(2.3前`HttpClient`,2.3后`HttpUrlConnection`) 首先`HttpClient`和`HttpUrlConnection` 这两种方式都支持`Https`协议,都是以流的形式进行上传或者下载数据,也可以说是以流的形式进行数据的传输,还有ipv6,以及连接池等功能。HttpClient这个拥有非常多的API,所以如果想要进行扩展的话,并且不破坏它的兼容性的话,很难进行扩展,也就是这个原因,Google在Android6.0的时候,直接就弃用了这个HttpClient. 而`HttpUrlConnection`相对来说就是比较轻量级了,API比较少,容易扩展,并且能够满足Android大部分的数据传输。比较经典的一个框架volley,在2.3版本以前都是使用`HttpClient`,在2.3以后就使用了`HttpUrlConnection`。 #### 6、java虚拟机和Dalvik虚拟机的区别? **Java虚拟机:** - java虚拟机基于栈。?基于栈的机器必须使用指令来载入和操作栈上数据,所需指令更多更多。 - java虚拟机运行的是java字节码。(java类会被编译成一个或多个字节码.class文件) **Dalvik虚拟机:** - dalvik虚拟机是基于寄存器的 - Dalvik运行的是自定义的.dex字节码格式。(java类被编译成.class文件后,会通过一个dx工具将所有的.class文件转换成一个.dex文件,然后dalvik虚拟机会从其中读取指令和数据 - 常量池已被修改为只使用32位的索引,以 简化解释器。 - 一个应用,一个虚拟机实例,一个进程(所有android应用的线程都是对应一个linux线程,都运行在自己的沙盒中,不同的应用在不同的进程中运行。每个android dalvik应用程序都被赋予了一个独立的linux PID(app_*)) #### 7、进程保活(不死进程) **此处延伸:进程的优先级是什么** #### 8、讲解一下Context? Context是一个抽象基类。在翻译为上下文,也可以理解为环境,是提供一些程序的运行环境基础信息。Context下有两个子类,`ContextWrapper`是上下文功能的封装类,而`ContextImpl`则是上下文功能的实现类。 而`ContextWrapper`又有三个直接的子类, `ContextThemeWrapper`、`Service`和`Application`。其中,`ContextThemeWrapper`是一个带主题的封装类,而它有一个直接子类就是Activity,所以Activity和Service以及Application的Context是不一样的,只有Activity需要主题,Service不需要主题。Context一共有三种类型,分别是Application、Activity和Service。这三个类虽然分别各种承担着不同的作用,但它们都属于Context的一种,而它们具体Context的功能则是由`ContextImpl`类去实现的,因此在绝大多数场景下,Activity、Service和Application这三种类型的Context都是可以通用的。不过有几种场景比较特殊,比如启动Activity,还有弹出Dialog。 出于安全原因的考虑,Android是不允许Activity或Dialog凭空出现的,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的Context,否则将会出错。 `getApplicationContext()`和`getApplication()`方法得到的对象都是同一个application对象,只是对象的类型不一样。 Context数量 = Activity数量 + Service数量 + 1 (1为Application) #### 9、理解Activity,View,Window三者关系 这个问题真的很不好回答。所以这里先来个算是比较恰当的比喻来形容下它们的关系吧。Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图)`LayoutInflater`像剪刀,`Xml`配置像窗花图纸。 > **1** Activity构造的时候会初始化一个Window,准确的说是`PhoneWindow`。 > **2** 这个`PhoneWindow`有一个“`ViewRoot`”,这个“`ViewRoot`”是一个View或者说`ViewGroup`,是最初始的根视图。 > **3** “`ViewRoot`”通过`addView`方法来一个个的添加View。比如`TextView`,`Button`等 > **4** 这些View的事件监听,是由`WindowManagerService`来接受消息,并且回调Activity函数。比如`onClickListener`,`onKeyDown`等。 #### 10、四种LaunchMode及其使用场景 **此处延伸**:栈(First In Last Out)与队列(First In First Out)的区别 **栈与队列的区别:** >1.?队列先进先出,栈先进后出 >2.?对插入和删除操作的"限定"。 栈是限定只能在表的一端进行插入和删除操作的线性表。 队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。 >3.?遍历数据速度不同 **standard 模式** 这是默认模式,每次激活Activity时都会创建Activity实例,并放入任务栈中。使用场景:大多数Activity。 **singleTop 模式** 如果在任务的栈顶正好存在该Activity的实例,就重用该实例( 会调用实例的 `onNewIntent()` ),否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例,只要不在栈顶,都会创建新的实例。使用场景如新闻类或者阅读类App的内容页面。 **singleTask 模式** 如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的 `onNewIntent()` )。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。如果栈中不存在该实例,将会创建新的实例放入栈中。使用场景如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走`onNewIntent`,并且会清空主界面上面的其他页面。 **singleInstance 模式** 在一个新栈中创建该Activity的实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的 `onNewIntent()` )。其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。使用场景如闹铃提醒,将闹铃提醒与闹铃设置分离。`singleInstance`不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (`singleInstance`) -> C,完全退出后,在此启动,首先打开的是B。 #### 11、View的绘制流程 #### 12、View,ViewGroup事件分发 #### 13、保存Activity状态 #### 14、Android中的几种动画 **帧动画**:指通过指定每一帧的图片和播放时间,有序的进行播放而形成动画效果,比如想听的律动条。 **补间动画**:指通过指定View的初始状态、变化时间、方式,通过一系列的算法去进行图形变换,从而形成动画效果,主要有Alpha、Scale、Translate、Rotate四种效果。注意:只是在视图层实现了动画效果,并没有真正改变View的属性,比如滑动列表,改变标题栏的透明度。 **属性动画**:在Android3.0的时候才支持,通过不断的改变View的属性,不断的重绘而形成动画效果。相比于视图动画,View的属性是真正改变了。比如view的旋转,放大,缩小。 #### 15、Android中跨进程通讯的几种方式 #### 16、AIDL理解 **此处延伸:简述Binder** ?**AIDL**: 每一个进程都有自己的Dalvik VM实例,都有自己的一块独立的内存,都在自己的内存上存储自己的数据,执行着自己的操作,都在自己的那片狭小的空间里过完自己的一生。而aidl就类似与两个进程之间的桥梁,使得两个进程之间可以进行数据的传输,跨进程通信有多种选择,比如 `BroadcastReceiver `, Messenger 等,但是 `BroadcastReceiver` 占用的系统资源比较多,如果是频繁的跨进程通信的话显然是不可取的;Messenger 进行跨进程通信时请求队列是同步进行的,无法并发执行。 **Binde机制简单理解**: 在Android系统的Binder机制中,是有`Client`,`Service`,`ServiceManager`,`Binder`驱动程序组成的,其中`Client`,`service`,`Service Manager`运行在用户空间,Binder驱动程序是运行在内核空间的。而Binder就是把这4种组件粘合在一块的粘合剂,其中核心的组件就是Binder驱动程序,`Service Manager`提供辅助管理的功能,而Client和Service正是在Binder驱动程序和`Service Manager`提供的基础设施上实现C/S 之间的通信。其中Binder驱动程序提供设备文件/dev/binder与用户控件进行交互, `Client`、`Service`,`Service Manager`通过open和ioctl文件操作相应的方法与Binder驱动程序进行通信。而Client和Service之间的进程间通信是通过Binder驱动程序间接实现的。而Binder Manager是一个守护进程,用来管理Service,并向Client提供查询Service接口的能力。 #### 17、Handler的原理 Android中主线程是不能进行耗时操作的,子线程是不能进行更新UI的。所以就有了handler,它的作用就是实现线程之间的通信。 handler整个流程中,主要有四个对象,`handler`,`Message`,`MessageQueue`,`Looper`。当应用创建的时候,就会在主线程中创建handler对象, 我们通过要传送的消息保存到`Message`中,handler通过调用`sendMessage`方法将`Message`发送到`MessageQueue`中,`Looper`对象就会不断的调用loop()方法 不断的从`MessageQueue`中取出Message交给handler进行处理。从而实现线程之间的通信。 #### 18、Binder机制原理 在Android系统的Binder机制中,是有`Client`,`Service`,`ServiceManager`,`Binder`驱动程序组成的,其中`Client`,`service`,`Service Manager`运行在用户空间,Binder驱动程序是运行在内核空间的。而Binder就是把这4种组件粘合在一块的粘合剂,其中核心的组件就是Binder驱动程序,`Service Manager`提供辅助管理的功能,而`Client`和`Service`正是在Binder驱动程序和`Service Manager`提供的基础设施上实现C/S 之间的通信。其中Binder驱动程序提供设备文件/dev/binder与用户控件进行交互,`Client`、`Service`,`Service Manager`通过open和ioctl文件操作相应的方法与Binder驱动程序进行通信。而Client和Service之间的进程间通信是通过Binder驱动程序间接实现的。而`Binder Manager`是一个守护进程,用来管理Service,并向Client提供查询Service接口的能力。 #### 19、热修复的原理 我们知道Java虚拟机 —— JVM 是加载类的class文件的,而Android虚拟机——Dalvik/ART VM 是加载类的`dex`文件, 而他们加载类的时候都需要`ClassLoader,ClassLoader`有一个子类`BaseDexClassLoader`,而`BaseDexClassLoader`下有一个 数组——`DexPathList`,是用来存放`dex`文件,当`BaseDexClassLoader`通过调用`findClass`方法时,实际上就是遍历数组, 找到相应的`dex`文件,找到,则直接将它return。而热修复的解决方法就是将新的`dex`添加到该集合中,并且是在旧的`dex`的前面, 所以就会优先被取出来并且return返回。 #### 20、Android内存泄露及管理 #### 21、Fragment与Fragment、Activity通信的方式 #### 22、Android UI适配 #### 23、app优化 #### 24、图片优化 >**(1)** 对图片本身进行操作。尽量不要使用`setImageBitmap`、`setImageResource`、`BitmapFactory.decodeResource`来设置一张大图,因为这些方法在完成decode后, >最终都是通过java层的`createBitmap`来完成的,需要消耗更多内存. >**(2)** 图片进行缩放的比例,SDK中建议其值是2的指数值,值越大会导致图片不清晰。 >**(3)** 不用的图片记得调用图片的recycle()方法 #### 25、HybridApp WebView和JS交互 #### 26、JAVA GC原理 #### 27、ANR #### 28、设计模式 #### 29、RxJava #### 30、MVP,MVC,MVVM **此处延伸**:手写mvp例子,与mvc之间的区别,mvp的优势 MVP模式,对应着Model--业务逻辑和实体模型,view--对应着activity,负责View的绘制以及与用户交互,Presenter--负责View和Model之间的交互,MVP模式是在MVC模式的基础上,将Model与View彻底分离使得项目的耦合性更低,在Mvc中项目中的activity对应着mvc中的`C--Controllor`,而项目中的逻辑处理都是在这个C中处理,同时View与Model之间的交互,也是也就是说,mvc中所有的逻辑交互和用户交互,都是放在`Controllor`中,也就是activity中。 View和model是可以直接通信的。而MVP模式则是分离的更加彻底,分工更加明确Model--业务逻辑和实体模型,view--负责与用户交互,Presenter 负责完成View于Model间的交互,MVP和MVC最大的区别是MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由`Presenter`完成。还有一点就是`Presenter`与`View`之间的交互是通过接口的 #### 31、手写算法(选择冒泡必须要会) #### 32、JNI? > **(1)** 安装和下载Cygwin,下载 Android NDK > **(2)** 在ndk项目中JNI接口的设计 > **(3)** 使用C/C++实现本地方法 > **(4)** JNI生成动态链接库.so文件 > **(5)** 将动态链接库复制到java工程,在java工程中调用,运行java工程即可 #### 33、RecyclerView和ListView的区别 `RecyclerView`可以完成`ListView`,`GridView`的效果,还可以完成瀑布流的效果。同时还可以设置列表的滚动方向(垂直或者水平); `RecyclerView`中view的复用不需要开发者自己写代码,系统已经帮封装完成了 `RecyclerView`可以进行局部刷新。 `RecyclerView`提供了API来实现item的动画效果。 **在性能上:** 如果需要频繁的刷新数据,需要添加动画,则`RecyclerView`有较大的优势。 如果只是作为列表展示,则两者区别并不是很大。 #### 34、Universal-ImageLoader,Picasso,Fresco,Glide对比 #### 35、Xutils, OKhttp, Volley, Retrofit对比 ### 最后 下面是辛苦给大家整理的学习路线,有需要的可以[点击这里免费获取](https://github.com/a120464/Android-P7/blob/master/Android%E5%BC%80%E5%8F%91%E4%B8%8D%E4%BC%9A%E8%BF%99%E4%BA%9B%EF%BC%9F%E5%A6%82%E4%BD%95%E9%9D%A2%E8%AF%95%E6%8B%BF%E9%AB%98%E8%96%AA%EF%BC%81.md) ![](http://www.icode9.com/i/li/?n=2&i=images/20210711/1626015235567800.jpg)
上一篇:2021年阿里Android面试题精选,送大厂面经一份!


下一篇:Android入门你值得拥有!三级缓存框架问题你都了解了吗