3W+字长文深度总结|Android程序员面试题精华版集合(内附思维导图)!

1、简述JVM中类的加载机制与加载过程?

1、概述:虚拟机把描述类的数据从Class文件加载到内存,并对数据 进行校验、转换解析和初始化,最终形成可以被虚拟直接使用的java类型,这就是虚拟机的类加载机制。

2、类加载的过程:加 载、验 证、准 备、解 析、初始化、使 用、卸载

3、关于初始化:
5种情况会触发类的初始化

1)遇到new,getstatic,putstatic,invokesstatic这四个字节码指令
时,如果类没有被初始化

2)使用java.lang.reflect包的方法对类进行反射时,如果类没
有被初始化,则先触发其初始化

3)当初始化一个类时,其父类没有被初始化,则需要父类先初始化

4)虚拟机启动时,用户需要制定一个执行的主类,虚拟机会先初始化这个类

5)JDK 1.7动态语言支持时,如果一个java.lang.invoke.MethodHandle实例后的解析结果REF_getStatic,REF_putStatic,REF_invokeStatic的方 法句柄,并且这个方法句柄所对应的类没有被初始化

2、类加载的过程

通过一个类的全限名来获取定义此类的二进制字节流,将字节流所代表的静态存储结构转化为方法区的运行时
数据结构在内存中生成一个代表这个类的java.lang.Class对象, 作为方法区这个类的各种数据的访问入口

3、JVM、Dalvik、ART三者的原理和区别?

JVM:是Java Virtual Machine的缩写,其并不是指某个特定的虚拟机实现,而指任何能够运行Java字节码(class文件)的虚拟机实现,比如oracle的HotspotVM

Dalvik:是Google写的一个用于Android的虚拟机,但其严格来说并不算JVM(没有遵守Java虚拟机规范,比
如其字节码格式是dex而非class)该虚拟机在5.0时被ART替代

ART:是Android Runtime的缩写,严格来说并不是一个虚拟机,在4.4~6.0时采用安装时全部编译为机器码的 方式实
现,7.0时默认不全部编译,采用解释执行+JIT+空闲时AOT以改善安装耗时ART在安卓4.4时加入,5.0取代dalvik作为唯一实现直到现在

4、请谈谈Java的内存回收机制?

内存分为栈(stack)和堆(heap)两部分:

栈记录了方法调用,每个线程拥有一个栈,栈的每一帧中保存有该方法调用的参数、局部变量、返回地址栈中被调用方法运行结束时,相应的帧会删除,参数和局部变量占用的空间也会释放,堆是用来存储对象的,堆区由所有线程共享

垃圾回收机制有:引用计数算法、可达性分析算法、标记清除算法、复制算法、标记整理算法、分代回收算法。

5、JMM是什么?它存在哪些问题?该如何解决?

就是Java内存模型。存在的问题就是多线程对共享数据的读写一致性问题,可以通过synchronized、cas、并发安全的数据结构、aqs 组件来解决

6、Android中进程和线程的关系? 区别?

  • 线程是CPU调度的最小单元,同时线程是一种有限的系统资源;
  • 进程一般指一个执行单元,在PC和移动设备上一个程序或则一个应用,
  • 一般来说,一个App程序至少有一个进程,一个进程至少有一个线程(包含与被包含的关系), 通俗来讲就是,在App这个工厂里面有一个进程,线程就是里面的生产线,但主线程(主生产线)只有一条,而子线程(副生产线)可以有多个。
  • 进程有自己独立的地址空间,而进程中的线程共享此地址空间,都可以并发执行。

7、如何开启多进程 ? 应用是否可以开启N个进程 ?

  • 在AndroidMenifest中给四大组件指定属性android:process开启多进程模式
  • 在内存允许的条件下可以开启N个进程

8、为何需要IPC?多进程通信可能会出现的问题?

  • 所有运行在不同进程的四大组件(Activity、Service、Receiver、ContentProvider)共享数据都会失
    败,这是由于Android为每个应用分配了独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这会导致在不同的虚拟机中访问同一个类的对象会产生多份副本。比如常用例子(通过开启多进程获取更大内存空间、两个或则多个应用之间共享数据、微信全家桶)
  • 一般来说,使用多进程通信会造成如下几方面的问题

1)静态成员和单例模式完全失效:独立的虚拟机造成

2)线程同步机制完全实效:独立的虚拟机造成

3)SharedPreferences的可靠性下降:这是因为Sp不支持两个进程并发进行读写,有一定几率导致数据丢失

4)Application会多次创建:Android系统在创建新的进程会分配独立的虚拟机,所以这个过程其实就是启动一个应用的过程,自然也会创建新的Application

9、Binder机制的作用和原理?

Linux系统将一个进程分为用户空间和内核空间。对于进程之间来说,用户空间的数据不可共享,内核空间的数据可共享,为了保证安全性和独立性,一个进程不能直接操作或者访问另一个进程,即Android的进程是相互独立、隔离的,这就需要跨进程之间的数据通信方式。

一次完整的 Binder IPC 通信过程通常是这样:

  • 首先 Binder 驱动在内核空间创建一个数据接收缓存区;
  • 接着在内核空间开辟一块内核缓存区,建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区和接收进程用户空间地址的映射关系;
  • 发送方进程通过系统调用 copyfromuser() 将数据 copy 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。

10、Bundle传递对象为什么需要序列化?Serialzable和Parcelable的区别?

  • 因为bundle传递数据时只支持基本数据类型,所以在传递对象时需要序列化转换成可存储或可传输的
    本质状态(字节流)。序列化后的对象可以在网络、IPC(比如启动另一个进程的Activity、Service和
    Reciver)之间进行传输,也可以存储到本地。
  • 序列化实现的两种方式:实现Serializable/Parcelable接口。不同点如图:

alt

11、讲讲AIDL?原理是什么?如何优化多模块都使用AIDL的情况?

  • AIDL(Android Interface Definition Language,Android接口定义语言):如果在一个进程中要调用另一个进程中对象的方法,可使用AIDL生成可序列化的参数,AIDL会生成一个服务端对象的代理类,通过它客户端实现间接调用服务端对象的方法。

  • AIDL的本质是系统提供了一套可快速实现Binder的工具。关键类和方法:

1)AIDL接口:继承IInterface。

2)Stub类:Binder的实现类,服务端通过这个类来提供服务。

3)Proxy类:服务器的本地代理,客户端通过这个类调用服务器的方法。

4)asInterface():客户端调用,将服务端的返回的Binder对象,转换成客户端所需要的AIDL接口类型对象。如果客户端和服务端位于统一进程,则直接返回Stub对象本身,否则返回系统封装后的Stub.proxy对象

5)asBinder():根据当前调用情况返回代理Proxy的Binder对象。

6)onTransact():运行服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理。

7)transact():运行在客户端,当客户端发起远程请求的同时将当前线程挂起。之后调用服务端的onTransact()直到远程请求返回,当前线程才继续执行。

  • 当有多个业务模块都需要AIDL来进行IPC,此时需要为每个模块创建特定的aidl文件,那么相应的
    Service就会很多。必然会出现系统资源耗费严重、应用过度重量级的问题。解决办法是建立Binder连
    接池,即将每个业务模块的Binder请求统一转发到一个远程Service中去执行,从而避免重复创建
    Service。
  • 工作原理:每个业务模块创建自己的AIDL接口并实现此接口,然后向服务端提供自己的唯一标识和其对应的Binder对象。服务端只需要一个Service,服务器提供一个queryBinder接口,它会根据业务模块的特征来返回相应的Binder对象,不同的业务模块拿到所需的Binder对象后就可进行远程方法的调用了

12、Activity中onNewIntent方法的调用时机和使用场景?

在该Activity的实例已经存在于Task和Back stack中(或者通俗的说可以通过按返回键返回到该Activity )时,当使用
intent来再次启动该Activity的时候,如果此次启动不创建该Activity的新实例,则系统会调用原有实例onNewIntent()
方法来处理此intent.

且在下面情况下系统不会创建该Activity的新实例:

1、如果该Activity在Manifest中的android:launchMode定义为singleTask或者singleInstance.

2、如果该Activity在Manifest中的android:launchMode定义为singleTop且该实例位于Backstack的栈顶.

3、如果该Activity在Manifest中的android:launchMode定义为singleTop,且上述intent包含Intent.FLAG_ACTIVITY_CLEAR_TOP标志

4、如果上述intent中包含Intent.FLAG_ACTIVITY_CLEAR_TOP标志和且包含Intent.FLAG_ACTIVITY_SINGLE_TOP标志.

5、如果上述intent中包含Intent.FLAG_ACTIVITY_SINGLE_TOP 标志且该实例位于Back stack的栈顶。
上述情况满足其一,则系统将不会创建该Activity的新实例.

13、Intent传输数据的大小有限制吗?如何解决?

Intent 中的 Bundle 是使用 Binder 机制进行数据传送的, 数据会写到内核空间, Binder 缓冲区域;
Binder 的缓冲区是有大小限制的, 有些 ROM 是 1M, 有些ROM 是 2M;这个限制定义在frameworks/native/libs/binder/processState.cpp 类 中 , 如果超过这个限制, 系统就会报错;

#define BINDER_VM_SIZE ((1*1024*1024) - (4096*2)) ;

因为 Binder 本身就是为了进程间频繁-灵活的通信所设计的, 并不是为了拷贝大量数据;如果非 ipc 就很简单了, static 变量, eventBus 之类的都可以;如果是 ipc, 一定要一次性传大文件, 可以用 file 或者socket;

14、说说ContentProvider、ContentResolver、ContentObserver 之间的关系?

ContentProvider:内容提供者, 用于对外提供数据,比如联系人应用中就是用了
ContentProvider:一个应用可以实现ContentProvider来提供给别的应用操作, 通过ContentResolver来操作别的应用数据

ContentResolver:内容解析者, 用于获取内容提供者提供的数据
ContentResolver.notifyChange(uri)发出消息

ContentObserver:内容监听者,可以监听数据的改变状态,观察(捕捉)特定的Uri引起的数据库的变化

ContentResolver.registerContentObserver()监听消息

概括:
使用ContentResolver来获取ContentProvider提供的数据, 同时注册ContentObserver监听数据的变化

15、说说Activity加载的流程?

App 启动流程(基于Android8.0):

点击桌面 App图标,Launcher进程采用 BinderIPC(具体为ActivityManager.getService 获取 AMS 实例) 向
system_server的AMS发起 startActivity请求,system_server 进程收到请求后,向 Zygote 进程发送创建进程的请求;

Zygote 进程 fork 出新的子进程,即 App 进程App 进程创建即初始化 ActivityThread,然后通过BinderIPC 向 system_server 进程的 AMS 发起attachApplication 请求,system_server 进程的 AMS 在收到attachApplication 请求后,做一系列操作后,通知 ApplicationThread bindApplication,然后发送H.BIND_APPLICATION 消息。

主线程收到 H.BIND_APPLICATION 消息,调用handleBindApplication 处理后做一系列的初始化操作,
初始化 Application 等,system_server 进程的 AMS 在 bindApplication 后,会调用 ActivityStackSupervisor.attachApplicationLocked, 之 后经过一系列操作,在 realStartActivityLocked 方法通过Binder IPC 向 App 进程发送scheduleLaunchActivity 请求;

App进程的 binder 线程(ApplicationThread)在收到请求后,通过 handler 向主线程发送LAUNCH_ACTIVITY 消息;主线程收到 message后经过 handleLaunchActivity,performLaunchActivity 方法,然后通过反射机制创建目标Activity;

通过 Activityattach方法创建 window并且和 Activity 关联,然后设置 WindowManager 用来管理 window, 然后通知 Activity 已创建,即调用 onCreate,然后调用 handleResumeActivity,Activity可见

16、自定义 Handler 时如何有效地避免内存泄漏问题?

  • 自定义的静态handler
  • 可以加一个弱引用
  • 还有一个主意的就是当你activity被销毁的时候如果还有消息没有发出去 就remove掉吧
  • removecallbacksandmessages去清除Message和Runnable 加null 写在生命周的ondestroy()就行

17、哪些情况下会导致oom问题?

  • 例如handler 在界面销毁的时候消息还未发送
  • file没有关流
  • 查询到结果还没有停止
  • 内部类持有外部类引用得不到释放
  • 不用的对象最好null 让GC回收一下
  • 图片资源什么的最好加一个软引用

18、一般什么情况下会导致内存泄漏问题?

  • 资源对象没关闭造成的内存泄漏(如 : Cursor、File 等)
  • ListView 的 Adapter 中没有使用缓存的ConvertView
  • Bitmap对象不在使用时调用recycle()释放内存
  • 集合中对象没清理造成的内存泄漏(特别是 static 修饰的集合)
  • 接收器、监听器注册没取消造成的内存泄漏
  • Activity 的 Context 造成的泄漏,可以使用ApplicationContext
  • Handler 造成的内存泄漏问题(一般由于 Handler 生命周期比其外部类的生命周期长引起的)

19、ANR 出现的场景以及解决方案?

在Android中,应用的响应性被活动管理器(Activity Manager)和窗口管理器(Window Manager)这两个系统服
务所监视。当用户触发了输入事件(如键盘输入,点 击按钮等),如果应用5秒内没有响应用户的输入事件,那么,
Android会认为该应用无响应,便弹出ANR对话框。而弹出ANR异常,也主要是为了提升用户体验。解决方案是对于耗时的操作,比如访问网络、访问数据库等操作,需要开辟子线程,在子线程处理耗时的操作,主线程主要实现UI的操作

20、谈谈Android中内存优化的方式?

关于内存泄漏,一般像单例模式的使用不当啊、集合的操作不当啊、资源的缺乏有效的回收机制啊、Handler、线程 的使
用不当等等都有可能引发内存泄漏。

  • 单例模式引发的内存泄漏:

原因:单例模式里的静态实例持有对象的引用,导致对象无法被回收,常见为持有Activity的引用

优化:改为持有Application的引用,或者不持有使用的时候传递。

  • 集合操作不当引发的内存泄漏:

原因:集合只增不减
优化:有对应的删除或卸载操作

  • 线程的操作不当引发的内存泄漏:

原因:线程持有对象的引用在后台执行,与对象的生命周期不一致

优化:静态实例+弱引用(WeakReference)方式,使其生命周期一致

  • 匿名内部类/非静态内部类操作不当引发的内存泄漏:

原因:内部类持有对象引用,导致无法释放,比如各种回调

优化:保持生命周期一致,改为静态实例+对象的弱引 用方式(WeakReference)

  • 常用的资源未关闭回收引发的内存泄漏:

原因:BroadcastReceiver,File,Cursor,IO流,Bitmap等资源使用未关闭

优化:使用后有对应的关闭和卸载机制

  • Handler使用不当造成的内存泄漏:

原因:Handler持有Activity的引用,其发送的Message 中持有Handler的引用,当队列处理Message的时间过长会导致
Handler无法被回收

优化:静态实例+弱引用(WeakReference)方式内存

21、谈谈布局优化的技巧?

  • 降低Overdraw(过度绘制),减少不必要的背景绘制
  • 减少嵌套层次及控件个数
  • 使用Canvas的clipRect和clipPath方法限制View的绘制区域
  • 通过imageDrawable方法进行设置避免ImageView的background和imageDrawable重叠
  • 借助ViewStub按需延迟加载
  • 选择合适的布局类型
  • 熟悉API尽量借助系统现有的属性来实现一些UI效果

注:因为实际开发与参考答案会有所不同,再者怕误导大家,所以这些面试题答案还是自己去理解!为了方便大家阅读们这里剩下的面试题全部整理成PDF手册。

内容体系全面

话不多说,先给大家看看,手册的内容结构:
在这里插入图片描述
手册目前共有Android部分,Java部分,Android Framework部分,Flutter,数据结构与算法,音视频等六个章节,共有 1000 多页,可以说基本涵盖了面试的必问考点

第一章 Java方面

  • 第一节 Java基础
  • 第二节 Java集合
  • 第三节 Java多线程
  • 第四节 Java虚拟机

在这里插入图片描述

第二章 Android 方面

  • 第一节 Android 四大组件相关
  • 第二节 Android 异步任务和消息机制
  • 第三节 Android UI 绘制相关
  • 第四节 Android 性能调优相关
  • 第五节 Android 中的 IPC
  • 第六节 Android 系统 SDK 相关
  • 第七节 第三方框架分析
  • 第八节 综合技术
  • 第九节 数据结构方面
  • 第十节 设计模式
  • 第十一节 计算机网络方面
  • 第十二节 Kotlin方面

在这里插入图片描述

第三章 音视频开发高频面试题

  • 为什么巨大的原始视频可以编码成很小的视频呢?这其中的技术是什么呢?
  • 怎么做到直播秒开优化?
  • 直方图在图像处理里面最重要的作用是什么?
  • 数字图像滤波有哪些方法?
  • 图像可以提取的特征有哪些?

在这里插入图片描述

第四章 Flutter高频面试题

  • 第一节 Dart部分

    • Dart 语言的特性?
    • Dart的一些重要概念?
    • dart是值传递还是引用传递?
    • Dart 多任务如何并行的?
    • 说一下 mixin?
  • 第二节 Flutter 部分

    • Flutter 特性有哪些?
    • Flutter 中的生命周期
    • Widget 和 element 和 RenderObject 之间的关系?
    • mixin extends implement 之间的关系?
    • Flutter 和 Dart的关系是什么?

在这里插入图片描述

第五章 算法高频面试题

  • 如何⾼效寻找素数
  • 如何运⽤⼆分查找算法
  • 如何⾼效解决接⾬⽔问题
  • 如何去除有序数组的重复元素
  • 如何⾼效进⾏模幂运算

在这里插入图片描述

第六章 Android Framework方面

  • 第一节 系统启动流程面试题解析
  • 第二节 Binder面试题解析
  • 第三节 Handler面试题解析
  • 第四节 AMS面试题解析

在这里插入图片描述

第七章 企业常见174道面试题

  • 1.SD卡
  • 2.android的数据存储方式
  • 3.BroadcastReceiver
  • 4.sp频繁操作会有什么后果?sp能存多少数据?
  • 5.dvm与jvm的区别
  • 6.ART
  • 7.Activity的生命周期
  • 8.Application能不能启动Activity
  • 9.Activity的状态都有哪些
  • 10.横竖屏切换时Activity的生命周期

在这里插入图片描述

结语

由于知识点涉及较广,因此将题目整理成PDF格式,需要的下方获取

猜你喜欢

转载自blog.csdn.net/Code1994/article/details/133185194