前言
此危急存亡之秋,内外经济皆很低迷,就业机会如此甚少,竟决然裸辞,昼夜难寐,内心十分慌张。。。翌日,遂撰写此文,暗自学习,以解内心之紧张,期早日求得岗位,得以温饱。
描述
Android 开发求者欲求一职,必先精于其技,历经考核。面试之中,多有问答,涵盖广泛,细致入微。兹略述数端,以供研习。
内容
其一,问于架构。欲知者,当能言 MVC、MVP、MVVM 之异同,尤要领会 Jetpack 组件,诸如 LiveData、ViewModel、DataBinding、Room 之用意。
https://juejin.cn/post/7197230639144828988
其二,思于组件。四大组件是何?然则活动(Activity)、服务(Service)、广播接收器(BroadcastReceiver)、内容提供者(ContentProvider);其用法、生命周期及其互动,皆需熟识。
ContentProvider 是 Android 系统中用于管理结构化数据访问的核心组件之一。它的主要作用是封装数据,并提供统一的接口供其他应用或组件(如 Activity、Service)访问数据。ContentProvider 的核心原理包括数据封装、URI 机制、权限控制和跨进程通信等。
7. 总结
ContentProvider 的核心原理包括:
数据封装与共享。
URI 机制用于标识数据。
权限控制确保数据安全。
跨进程通信通过 Binder 实现。
提供标准的 CRUD 接口。
通过 ContentProvider,开发者可以实现安全、高效的数据共享和管理,同时为其他应用提供统一的访问接口。
其三,思虑线程处理。面试者多喜探究于异步任务,若 AsyncTask、Handler、Thread 及新兴之协程(Coroutines)。故而应知线程切换、同步锁及死锁之事。
同步锁(Synchronization Lock)
在多线程编程中,同步锁用于控制多个线程对共享资源的访问,以防止数据竞争和不一致性问题。同步锁确保在同一时间只有一个线程可以访问共享资源,从而保证线程安全。
常见的同步锁机制
1.synchronized同步锁
2.ReentrantLock可重入锁(Lock接口)
3.ReentrantReadWriteLock可重入读写锁(ReadWriteLock接口)
4.StampedLock戳锁
https://www.cnblogs.com/dennyzhangdd/p/6925473.html
死锁(Deadlock)
死锁是指两个或多个线程在执行过程中,因争夺资源而造成的一种互相等待的现象,导致这些线程都无法继续执行下去。
死锁产生的四个必要条件
互斥条件(Mutual Exclusion):
资源一次只能被一个线程占用。
占有并等待(Hold and Wait):
线程持有至少一个资源,并等待获取其他被占用的资源。
不可抢占条件(No Preemption):
已分配给线程的资源不能被其他线程强行抢占,必须由线程自行释放。
循环等待条件(Circular Wait):
存在一个线程等待的循环链,每个线程都在等待下一个线程所占用的资源。

在这个例子中,thread1持有lock1并等待lock2,而thread2持有lock2并等待lock1,导致两个线程互相等待,形成死锁。
死锁的预防和避免
破坏互斥条件:
尽量避免使用互斥锁,或者使用可共享的资源。
破坏占有并等待条件:
要求线程一次性获取所有需要的资源,或者在获取新资源前释放已持有的资源。
破坏非抢占条件:
允许系统强行抢占线程持有的资源。
破坏循环等待条件:
对资源进行排序,要求线程按顺序获取资源,避免循环等待。
死锁的检测和恢复
死锁检测:
通过资源分配图等算法检测系统中是否存在死锁。
死锁恢复:
终止一个或多个线程以打破死锁。
回滚线程到某个安全状态,释放资源并重新执行。
总结
同步锁是保证多线程程序正确性的重要机制,但不当使用可能导致死锁。理解死锁的产生条件和预防方法,可以帮助开发者编写更健壮的多线程程序。在实际开发中,应尽量避免复杂的锁依赖关系,使用工具和算法检测和预防死锁。
其四,析于数据存储。求知者宜晓 SharedPreferences、SQLite、File 存储及网络层 OkHttp、Retrofit 之功效。必引材料配合与高效使用。
其五,问于界面优化。其设计尤重,须思维 RecyclerView 用法,布局优化及动画之效,与 ConstraintLayout 方能胜任。
其余者,尚有问及内存管理,垃圾回收机制,及耗电优化之法。更有安防之策,故而凡于敏感信息、权限请求,皆需戒慎乎其事。
是以应聘者需勤修研习,方能见智见功乎此途。
一. 字节跳动
1.根服务器是什么?
根服务器(Root Name Server)是域名系统(DNS)架构中的一个关键组件,它的主要功能是帮助将人类可读的域名(如example.com)解析为计算机可读的IP地址。在DNS层次结构中,根服务器位于最顶部,负责指引查询者(通常是递归DNS解析器)到顶级域名服务器(如.com、.org、.net等)。
以下是关于根服务器的几个关键点:
数量和分布:全球共有13组根服务器,这些服务器用字母A到M标识。虽然组的数量是13,但实际上每组包含许多实例,全球分布以提供更好的冗余性和低延迟。这些服务器通过一种称为Anycast的技术部署,以服务于全球不同的地理区域。
管理机构:根服务器不是由单一的组织管理的,而是由多个组织负责,包括ICANN、VeriSign、NASA等。其中负责这些服务器的组织必须确保其运行的稳定性和安全性。
功能和角色:根服务器不存储域名的完整信息,而是将查询者引导到正确的顶级域名(TLD)服务器。例如,当你输入一个网址时,如果你的本地DNS解析器不知道该如何解析,它会发出一个请求到根服务器,根服务器会告诉它去哪个TLD服务器寻找更详细的信息。
稳定性和安全性:根服务器的运行稳定性至关重要,因为它们是互联网基础架构的一个重要部分。确保根服务器的安全性同样关键,因为如果根服务器受到攻击或故障,可能会导致大范围的互联网中断。
DNS解析过程中的作用:在DNS解析的过程中,根服务器是第一步。递归解析器首先联系根服务器并获取TLD信息,然后递归解析器根据根服务器的指引访问相应的TLD服务器获取更下一层的信息,直至获取最终的域名解析结果。
根服务器的设计和部署旨在使其极其稳定和可用,以确保全球互联网的正常运行。
2.根据实际情况写SQL语句。
3.数据库表的内联
4.一个单核CPU最多可以有多少个线程?
5.定义一个数组 int a[1000010],它的空间回收是怎样的?
6.定义了一个结构体user,在一个函数中使用了 user,它在函数的结束的时候是否回收空间,要不要用delete?
7.定义了一个int a,在函数执行完成以后它会何去何从?
8.算法题:二叉树的程序遍历
10.TCP位于TCP/IP协议的哪一层,它和UDP协议又有什么区别呢?
TCP位于TCP/IP协议模型的传输层。
TCP/IP协议模型的四层结构:
应用层:提供应用程序通信服务(如HTTP、FTP、SMTP等)。
传输层:负责端到端的数据传输,主要协议有TCP和UDP。
网络层:负责数据包的路由和转发,主要协议是IP。
网络接口层:负责物理网络的数据传输(如以太网、Wi-Fi等)。
TCP与UDP的区别:
连接方式:
TCP:面向连接,通信前需通过三次握手建立连接,通信结束后通过四次挥手断开连接。
UDP:无连接,直接发送数据,无需建立和断开连接。
可靠性:
TCP:提供可靠传输,通过确认、重传等机制确保数据无误且按序到达。
UDP:不保证可靠性,数据可能丢失、重复或乱序。
传输效率:
TCP:由于复杂的控制机制,传输效率较低。
UDP:简单高效,适合对实时性要求高的场景。
数据顺序:
TCP:保证数据按发送顺序到达。
UDP:不保证顺序。
流量控制:
TCP:通过滑动窗口机制进行流量控制。
UDP:无流量控制。
拥塞控制:
TCP:有拥塞控制机制,避免网络过载。
UDP:无拥塞控制。
头部大小:
TCP:头部较大,至少20字节。
UDP:头部较小,仅8字节。
应用场景:
TCP:适用于要求可靠传输的场景,如网页浏览、文件传输、电子邮件等。
UDP:适用于实时性要求高的场景,如视频流、在线游戏、DNS查询等。
总结:
TCP:可靠、面向连接,适合对数据完整性要求高的场景。
UDP:高效、无连接,适合对实时性要求高的场景。
11.Http请求Get和Post的异同?
HTTP请求中,GET和POST是最常用的两种方法,它们在用途、数据传输方式、安全性等方面有显著区别。
相同点:
基于HTTP协议:两者都遵循HTTP协议,用于客户端与服务器之间的通信。
请求-响应模型:客户端发送请求,服务器返回响应。
可传输数据:虽然GET通常用于获取数据,POST用于提交数据,但两者都可以携带数据。
不同点:
用途:
GET:主要用于请求数据,通常用于获取资源(如网页、图片等)。
POST:主要用于提交数据,通常用于提交表单、上传文件等。
数据传输方式:
GET:将数据附加在URL后,以查询字符串的形式发送(如?key1=value1&key2=value2)。
POST:将数据放在请求体中发送,不会显示在URL中。
数据大小限制:
GET:受URL长度限制(通常为2048字符),不适合传输大量数据。
POST:无严格限制,适合传输大量数据(如文件上传)。
安全性:
GET:数据暴露在URL中,容易被缓存、记录,安全性较低。
POST:数据在请求体中,相对更安全,但仍需加密(如HTTPS)以确保安全。
幂等性:
GET:是幂等的,多次请求同一资源不会对服务器状态产生影响。
POST:非幂等,多次提交可能导致服务器状态变化(如重复提交订单)。
缓存:
GET:可以被浏览器缓存,适合请求静态资源。
POST:通常不会被缓存。
可见性:
GET:数据在URL中可见,适合用于书签或分享链接。
POST:数据不可见,不适合直接分享。
使用场景:
GET:适用于获取数据,如搜索、分页、查看资源等。
POST:适用于提交数据,如登录、注册、文件上传等。
总结:
GET:适合获取数据,数据暴露在URL中,有长度限制,安全性较低。
POST:适合提交数据,数据在请求体中,无长度限制,安全性较高。
13.什么是线程,什么是进程,如何管理线程和进程?
https://blog.csdn.net/qq_62729660/article/details/145907776
在Android中,进程管理是系统资源管理的核心部分,直接影响应用的性能、响应速度和电池寿命。Android系统通过独特的进程管理机制,确保多个应用能够高效、安全地运行。以下是Android进程管理的关键点:
1. 进程生命周期
Android进程的生命周期由系统根据应用组件的状态和资源需求动态管理。进程的优先级会根据其运行状态变化,系统可能会在资源不足时终止低优先级的进程。
2. 进程优先级
Android根据进程中的组件状态将其分为不同的优先级,优先级从高到低依次为:
前台进程(Foreground Process):
正在与用户交互的进程(如Activity在前台运行)。
包含正在运行的前台Service(如音乐播放)。
包含正在执行生命周期回调的组件(如onCreate()、onResume())。
系统会尽量避免终止前台进程。
可见进程(Visible Process):
包含不在前台但仍对用户可见的Activity(如弹出对话框)。
包含绑定到可见Activity的Service。
系统仅在极端情况下终止可见进程。
服务进程(Service Process):
包含正在运行的后台Service(如下载文件)。
如果没有更高优先级的进程需要资源,系统会保留服务进程。
后台进程(Background Process):
包含不可见的Activity(如按下Home键后的应用)。
系统可能会根据资源需求终止后台进程。
空进程(Empty Process):
不包含任何活动组件的进程,仅作为缓存保留。
系统会优先终止空进程以释放资源。
3. 进程创建与销毁
进程创建:
当应用启动时,系统会为其创建一个主进程。
每个应用默认运行在独立的进程中,进程名通常与包名相同。
可以通过AndroidManifest.xml中的android:process属性为组件指定独立进程。
进程销毁:
当系统资源不足时,会按照优先级终止低优先级的进程。
进程销毁后,其状态和数据会丢失,那么如何恢复数据呢?

4. 多进程应用
Android允许应用通过多进程运行不同的组件,通常用于以下场景:
隔离组件:将某些组件(如Service)运行在独立进程中,避免主进程崩溃影响其他组件。
提升性能:将耗时任务(如大量计算)放在独立进程中,避免阻塞主进程。
共享数据:通过ContentProvider或Binder机制实现进程间通信(IPC)。
示例:在AndroidManifest.xml中为Service指定独立进程:

5. 进程间通信(IPC)
Android提供了多种进程间通信机制:
Binder:
最常用的IPC机制,基于AIDL(Android Interface Definition Language)实现。
用于跨进程调用方法。
Messenger:
基于Binder的轻量级IPC机制,适合简单的消息传递。
ContentProvider:
用于跨进程共享数据,如访问联系人、媒体文件等。
Socket:
基于网络的IPC机制,适合远程通信。
文件或SharedPreferences:
通过文件或SharedPreferences共享数据,但效率较低。
6. 进程保活
为了确保关键进程不被系统终止,开发者可以采用以下方法:
前台Service:
通过startForeground()将Service提升为前台服务。
必须显示一个持续的通知。
JobScheduler或WorkManager:
用于调度后台任务,系统会优化资源分配。
AlarmManager:
用于定时唤醒进程,但过度使用会影响电池寿命。
双进程守护:
通过两个进程互相监控,确保至少一个进程存活。
7. 进程管理工具
ADB命令:
查看进程信息:adb shell ps。
终止进程:adb shell am kill <package_name>。
Android Studio Profiler:
监控应用的进程状态、内存使用和CPU占用。
第三方工具:
如LeakCanary检测内存泄漏,StrictMode检测主线程阻塞。
8. 注意事项
避免滥用多进程:多进程会增加内存开销和复杂性。
合理使用保活机制:过度保活可能导致系统资源浪费和电池消耗。
优化内存使用:避免内存泄漏和过度占用内存,减少被系统终止的风险。
总结
Android进程管理通过动态调整进程优先级和资源分配,确保系统高效运行。开发者应理解进程生命周期、优先级和IPC机制,合理设计应用架构,避免资源浪费和性能问题。
安卓线程间通信机制:

14. 安卓进程间通信之AIDL的理解
在Android中,AIDL(Android Interface Definition Language) 是一种用于实现进程间通信(IPC)的机制,允许不同进程之间通过定义接口进行方法调用和数据传递。AIDL通常用于跨进程调用Service中的方法,适合复杂的IPC场景。
1. AIDL的核心概念
接口定义:AIDL通过定义接口来描述跨进程通信的方法。
数据类型支持:
基本数据类型(如int、float、boolean等)。
String、CharSequence。
List、Map(元素必须是AIDL支持的类型)。
自定义Parcelable对象。
Binder:AIDL的实现基于Binder机制,Binder是Android的IPC核心。
2. AIDL的使用步骤
步骤1:定义AIDL接口
在src/main/aidl目录下创建AIDL文件(如IMyService.aidl),定义接口方法。

步骤2:实现AIDL接口
在Service中实现AIDL接口。

步骤3:在AndroidManifest.xml中声明Service

步骤4:客户端绑定Service并调用方法
在客户端中绑定Service,并通过AIDL接口调用方法。

3. AIDL支持的数据类型
基本数据类型:int、long、float、double、boolean、char、byte。
String和CharSequence。
List和Map:元素必须是AIDL支持的类型。
Parcelable对象:自定义对象需要实现Parcelable接口。
4. AIDL的优缺点
优点:
支持复杂的跨进程通信。
支持同步和异步调用。
适合需要高性能的IPC场景。
缺点:
实现较复杂,需要定义AIDL接口和实现类。
不支持直接传递非Parcelable对象。
5. AIDL与Messenger的对比

6. 总结
AIDL是Android中实现复杂进程间通信的强大工具,适合需要高性能和多方法调用的场景。通过定义接口、实现Service和绑定Service,开发者可以轻松实现跨进程通信。对于简单的IPC需求,可以考虑使用Messenger或Intent。
15.CPU调度算法的理解
16.HashMap的扩容,为什么是2倍,为什么size是2的幂次方?
是为了尽可能的减少Hash碰撞。
17.算法题:给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = n?找出所有满足条件且不重复的三元组。
二. 大疆
1.如何检测内存泄漏,在实际开发中应当如何避免内存泄露?
在Android开发中,内存泄漏是一个常见问题,可能导致应用性能下降甚至崩溃。以下是检测和避免内存泄漏的方法:
检测内存泄漏
使用 LeakCanary
LeakCanary 是一个专门用于检测 Android 内存泄漏的库。
集成步骤:

集成后,LeakCanary 会自动检测内存泄漏并生成报告。
Android Profiler
Android Studio 自带的工具,用于分析内存使用情况。
使用步骤:
打开 Android Studio。
点击 View > Tool Windows > Profiler。
运行应用并选择 Memory 选项卡。
检查内存分配和对象引用,查找未释放的对象。
Heap Dump 分析
使用 Android Profiler 生成堆转储文件(Heap Dump),分析内存中的对象。
检查是否有对象未被释放,特别是 Activity、Fragment 等。
日志和代码审查
在关键生命周期方法(如 onDestroy())中添加日志,检查对象是否被正确释放。
定期进行代码审查,重点关注静态变量、单例、匿名内部类等可能导致内存泄漏的地方。
避免内存泄漏
避免静态引用
静态变量(如 static Context)会阻止垃圾回收器回收对象。
如果需要 Context,使用 Application Context 而不是 Activity Context。
正确处理生命周期
在 Activity 或 Fragment 销毁时,释放资源或取消异步任务。
例如,在 onDestroy() 中取消网络请求或注销监听器。
避免匿名内部类
匿名内部类(如 Runnable、Handler)会隐式持有外部类的引用,导致内存泄漏。
使用静态内部类或弱引用(WeakReference)代替。
使用弱引用(WeakReference)
对于可能持有 Activity 或 Fragment 引用的对象,使用 WeakReference。
示例:

及时注销监听器
在 Activity 或 Fragment 销毁时,注销广播接收器、事件监听器等。
示例:

避免单例模式滥用
单例模式可能导致内存泄漏,特别是当单例持有 Context 时。
如果需要 Context,使用 Application Context。
使用 ViewModel 和 LiveData
ViewModel 和 LiveData 是 Android Jetpack 组件,能够更好地管理 UI 相关的数据,避免内存泄漏。
ViewModel 的生命周期与 Activity/Fragment 分离,不会因为配置变化(如屏幕旋转)而泄漏。
避免长时间运行的任务
长时间运行的任务(如网络请求)应该在后台线程执行,并在 Activity/Fragment 销毁时取消。
使用 Lifecycle 组件确保任务与生命周期同步。
示例代码
避免 Handler 内存泄漏

使用 ViewModel 和 LiveData

2.Handler,loop和HandlerThread之间的关系
3.1个线程中的loop是否可以对应多个Handler
4.如何理解安卓中的异步任务?
5.字节流和字符类的区别
6.如何理解平衡二叉树
7.如何判断单向链表中是否存在环
8.什么是网络窗口滑动概念?
9.三次握手四次挥手分别是什么?
10.IP和掩码的关系
11.C语言基础知识 sizeof 指针、数组的大小
12.局部变量存在哪里,malloc的变量在哪里
13.Linux怎么搜索所有.so文件
14.单链表和双向链表是什么?
15.怎样实现多态?
三. 宝马诚迈
Android
1.已知有个启动模式为singleTop的Activity再次启动一个一模一样的Activity,问:页面数据如何加载?
2.安卓Activity之间的数据传递有哪些方式?
3.Hander,Looper机制
4.java虚拟机jvm
https://www.cnblogs.com/hnusthuyanhua/p/12979977.html
https://baijiahao.baidu.com/s?id=1803976026174761216&wfr=spider&for=pc
5.OkHttp架构中用到了哪些设计模式? 于普通的HttpClient/HttpUrlConnection请求相比较有哪些优势?
https://zhuanlan.zhihu.com/p/606988183
6.安卓常见的布局有哪些?
7.Android有哪几种动画? 请详细说明
https://zhuanlan.zhihu.com/p/410426799
8.Serializable 和 Parcelable有什么不同点?
https://www.jianshu.com/p/c63b23305e37
9.安卓View事件的传递是怎样的?
https://blog.csdn.net/aphrodite1314/article/details/111476218
10.父View是wrap_content,子View1是match_parent,会测量几次宽高,如果再嵌套View2又会测量几次呢?




以上可以看出,每增加一层ViewGroup的嵌套则会比上一级多测量3次,以此类推。
11.请详细说明Http和Https的区别
https://zhuanlan.zhihu.com/p/701521059
12.给定一张1000*1000尺寸的图片,问该图片占用多大的内存空间?
计算公式:图片占用内存 = bitmap 宽 * bitmap 高 * 每个像素占用的字节数
https://blog.csdn.net/2401_84009597/article/details/137577839
Kotlin
1.WithContext含义
在 Kotlin 协程中,withContext 是一个挂起函数,用于切换协程的上下文(Coroutine Context)并在指定上下文中执行代码块,最后返回代码块的结果。它是协程中实现异步代码同步化的关键工具,能简化多线程或异步操作的管理。
核心特性
切换上下文
临时切换到指定的 CoroutineContext(如 Dispatchers.IO、Dispatchers.Main),执行代码块后自动恢复原上下文。
例如:从主线程切换到 IO 线程执行网络请求,再切回主线程更新 UI。
返回结果
返回代码块中最后一行的结果(类似于 run 或 let 的作用域函数)。
非阻塞
是挂起函数(suspend),不会阻塞当前线程,而是挂起协程,直到代码块执行完成。
基本用法
// 在协程中调用viewModelScope.launch(Dispatchers.Main){// 主线程
val result=withContext(Dispatchers.IO){// 切换到 IO 线程
// 执行耗时操作(如网络请求、数据库查询)
fetchDataFromNetwork()
}
// 自动切回主线程,更新
UIupdateUI(result)}
关键点
1. 上下文(Context)的作用
withContext 的入参是 CoroutineContext,可以是:
调度器(Dispatcher):决定代码块在哪个线程池执行(如 Dispatchers.IO、Dispatchers.Default)。
其他上下文元素:如协程名称、异常处理器(CoroutineName、CoroutineExceptionHandler)。
2. 与 launch/async 的区别
launch:启动新协程,返回 Job,不关心结果。
async:启动新协程,返回 Deferred<T>(类似 Future),通过 await() 获取结果。
withContext:不启动新协程,只在当前协程中切换上下文,直接返回结果。
3. 与 runBlocking 的区别
runBlocking:阻塞当前线程,直到内部代码块完成。
withContext:挂起协程(非阻塞),只能在协程或其他挂起函数中调用。
2.let和apply的区别
在 Kotlin 中,let 和 apply 作为作用域函数,核心区别体现在 作用域参数、返回值类型 和 适用场景 三个方面:
1. 作用域参数
let
通过 it 访问调用对象,需显式使用 it 或自定义参数名引用对象。
person?.let { it.name = "John" } // 使用 it
person?.let { p -> p.age = 30 } // 自定义参数名
apply
通过 this 访问调用对象(可省略 this 直接调用成员),隐式引用上下文。
person.apply {
name = "John" // 等价于 this.name = "John"
age = 30
}
2. 返回值类型
let
返回 Lambda 表达式的结果(最后一行代码的返回值),常用于转换或处理对象后返回新值。
val length = person.name?.let { // 返回 name 的长度(Int 类型)
it.length
}
apply
返回 调用对象本身,适用于链式配置对象属性或调用方法。
val person = Person().apply { // 返回 Person 对象
name ="John"
age =30
}
3. 适用场景
let 的典型场景
空安全检查(结合 ?.let)12。
对象转换或链式操作(如计算结果并传递)37。
apply 的典型场景
初始化对象属性(如创建对象后批量配置)14。
链式调用中保留对象自身引用27。
总结对比表

3.如何等到两个网络请求都结束后在执行后续逻辑
async函数
4.Compose使用
算法题:实现快速排序
https://leetcode.cn/discuss/post/3566135/shi-da-pai-xu-cong-ru-men-dao-ru-zhui-by-pl2j/
https://blog.csdn.net/zl_StepByStep/article/details/80098718
https://blog.csdn.net/ji_meng/article/details/123871016
四. 天翼数字生活
1. Glide缓存机制
https://blog.csdn.net/y2653904/article/details/144625256
2. 基本按照简历上的内容进行问答
3.安卓崩溃信息如何收集? 同理崩溃分析工具Sentry的原理又是什么呢?
Firebase Crashlytics 和 Sentry 是最常用的崩溃分析工具,功能强大且易于集成。
崩溃信息收集的原理:
1. 使用 Thread.setDefaultUncaughtExceptionHandler 捕获全局崩溃
原理:通过设置默认的未捕获异常处理器,捕获应用中所有未处理的异常。
步骤:
实现自定义的 UncaughtExceptionHandler。
在 uncaughtException 方法中收集崩溃信息。
将崩溃信息保存到本地文件或上传到服务器。

五. 芷间科技
1. RecyclerView视图复用的原理是什么? RecyclerView在使用时有没有出现内存泄漏的情况,如果有是怎么检测的?
https://github.com/fanshanhong/note/blob/master/Android/%E7%B3%BB%E7%BB%9F/View/RecyclerView%E7%9A%84%E5%9B%9E%E6%94%B6%E5%A4%8D%E7%94%A8%E7%BC%93%E5%AD%98%E6%9C%BA%E5%88%B6.md
2. Looper是如何保证死循环不会卡死主线程的? ThreadLocal的作用是什么?Handler的原理是什么?
2.1 Looper保证循环不会卡死主线程的方案
nativePollOnce() 是 Android 中 MessageQueue 类的一个 JNI 方法,用于实现线程的消息等待机制。它是 Android 消息循环(Looper)的核心部分,主要负责线程的休眠和唤醒。
作用
nativePollOnce() 的作用是让当前线程进入等待状态,直到以下条件之一满足:
消息队列中有新消息:当 MessageQueue 中有新的消息需要处理时,线程会被唤醒。
超时时间到达:如果设置了超时时间(timeoutMillis),线程会在超时后自动唤醒。
外部唤醒:通过 Looper 的 wake() 方法可以主动唤醒线程。
工作原理
消息队列的等待机制
Android 的消息队列(MessageQueue)是基于 epoll 或类似的 I/O 多路复用机制实现的。
当消息队列为空时,nativePollOnce() 会调用底层的 epoll_wait() 方法,使线程进入休眠状态,避免无意义的 CPU 占用。
线程的休眠与唤醒
当有新消息加入消息队列时,系统会通过文件描述符(fd)的机制唤醒线程。
唤醒后,nativePollOnce() 返回,线程继续处理消息。
超时机制
nativePollOnce() 可以接受一个超时参数(timeoutMillis),表示最长等待时间。
如果超时时间到达,即使没有新消息,线程也会被唤醒。

2.2 ThreadLocal的作用
ThreadLocal 在 Handler 中的作用
存储线程本地的 Looper
每个线程只能有一个 Looper,Looper 通过 ThreadLocal 存储在当前线程中。
当调用 Looper.myLooper() 时,会从当前线程的 ThreadLocal 中获取与该线程关联的 Looper。
确保 Looper 的线程隔离
Handler 需要与特定的 Looper 绑定,而 Looper 是与线程绑定的。
通过 ThreadLocal,可以确保每个线程只能访问自己的 Looper,而不会访问到其他线程的 Looper。
支持主线程和子线程的 Handler 机制
Android 的主线程(UI 线程)默认会创建一个 Looper,并通过 ThreadLocal 存储。
开发者也可以在子线程中创建 Looper,并通过 ThreadLocal 实现线程本地的存储。

ThreadLocal 的介绍
ThreadLocal 是 Java 中的一个类,用于实现线程本地存储(Thread-Local Storage)。它的主要作用是为每个线程提供独立的变量副本,使得每个线程都可以独立地操作自己的变量,而不会影响其他线程中的同名变量。
核心作用
线程隔离
ThreadLocal 为每个线程维护一个独立的变量副本,确保线程之间的数据隔离。
每个线程只能访问和修改自己的变量副本,不会干扰其他线程的数据。
避免线程安全问题
由于 ThreadLocal 为每个线程提供了独立的变量副本,因此不需要额外的同步机制(如 synchronized 或 Lock)来保证线程安全。
简化参数传递
在某些场景中,ThreadLocal 可以用于在线程执行过程中隐式传递参数,避免在方法调用链中显式传递参数。
实现原理
ThreadLocal 的实现依赖于 Thread 类中的一个内部数据结构 ThreadLocalMap:
每个线程(Thread 对象)内部都有一个 ThreadLocalMap,用于存储该线程的所有 ThreadLocal 变量。
ThreadLocalMap 是一个自定义的哈希表,键是 ThreadLocal 对象,值是该线程对应的变量副本。
当调用 ThreadLocal.get() 或 ThreadLocal.set() 时,会从当前线程的 ThreadLocalMap 中获取或设置变量。
3. AMS的原理是什么?
4.自定义View的流程以及方式有哪些?
5.如何封装一个网络请求库,需要注意哪些问题?
6.Activity生命周期问题
6.1. ActivityA跳转到ActivityB时请问A,B两个Activity的生命周期是怎样的?
https://www.jianshu.com/p/161760f18ea5
6.2. 存在一个Activity在前台,此时屏幕息屏,当重新打开屏幕时该Activity的生命周期又是怎样的?
https://www.jianshu.com/p/161760f18ea5
7. 进程和线程的区别以及应用场景?
8. 给到一个商城首页应当如何实现?有哪些方案可以实现?
9.不同进程下的两个Activity如何跳转?
即使 Activity 运行在不同进程中,你仍然可以使用 Intent 来启动目标 Activity。Android 系统会自动处理进程间的通信。
10.线程池的种类有哪些? 如何理解线程池机制?
https://blog.csdn.net/MISSXIAOJJ/article/details/144775003
六.江苏春雨文化教育集团
1. 不同设备屏幕尺寸的适配
2. 移动设备答题功能实现方案
3. Activity的每个生命周期具体会做些什么事情?
4. 自我实现一个网络请求框架库应该做哪些事情?需要注意什么?
七.VIVO
1.性能优化相关的
2.日常性能优化案例分析
3.如何分析内存泄漏
4.内存过高会导致什么问题?
5. 播放器的原理分析
6. GC垃圾回收器的原理
八.小米-电视视频播放器
1. 有没有做过组件化,结合具体实例说明
2. 内存优化相关的
3. 有没有了解过视频流相关的内容
4. 日志收集有哪些作用
三. 2024年面试题
ANR问题:探讨如何识别和预防应用程序无响应的情况,包括合理安排主线程任务,减少阻塞操作以及正确使用子线程。
内存溢出(OOM)防治:介绍如何通过内存分析工具发现并解决内存消耗过大的问题,比如合理管理Bitmap、适当使用缓存策略、及时释放不再使用的资源等。
内存抖动(Memory Churn)与优化:讲解如何通过减少短时间内的大量对象创建与销毁,以降低内存分配频率,确保应用运行更加平稳。
内存泄漏(Memory Leak)检测与修复:阐述如何运用各种工具和技术定位内存泄漏源,并给出常见的内存泄漏场景及其解决方案。
UI流畅度提升:探讨如何优化界面渲染效率,包括采用硬件加速、避免不必要的布局嵌套、合理调度动画帧率、减少Overdraw等措施。
冷启动优化(Cold Start Time):分享如何缩短应用首次启动时间,可能涉及到dex分包、资源压缩、懒加载策略以及代码层面的优化手段。
Android SDK的定义与作用:考察应聘者对Android SDK的理解,包括其提供的库、示例代码、开发工具和模拟器系统。
Activity生命周期:讨论在不同生命周期状态中通常执行的操作,如onCreate()、onStart()、onResume()等。
Intent、Intent Filter和BroadcastReceiver的作用:解释这些Android组件间通信的基础知识。
Service在Android中的作用:探讨Service作为一种后台执行长时间运行操作的组件。
Content Provider的作用:解释Content Provider作为Android中数据封装和共享机制的功能。
Android中的Handler和Looper:讨论Handler和Looper在Android中的作用,以及它们如何处理与线程相关的Message和Runnable对象。
Android中的权限系统:解释Android的权限系统如何控制应用程序对敏感数据和设备功能的访问。
四. 具体的面试题
一张图片100x100在内存中的大小?
Bitmap压缩,质量100%与90%的区别?
TraceView的使用,查找CPU占用
Android四大组件的onCreate/onReceiver方法中Thread.sleep(),会产生几个ANR?
如何优化View层次过深问题,选择哪个布局比较好?
为何要用 ContentProvider?它与 sql 的实现上有什么区别?
app对内存是如何限制的? 应该如何合理使用内存?
如何对apk进行瘦身
说下冷启动与热启动是什么, 区别, 如何优化, 使用场景等
LeakCanray 2.0为啥不需要在application里调install?
怎样检测函数执行是否卡顿
为什么冷启动会有白屏黑屏问题?
EventBus框架的原理是什么?
https://zhuanlan.zhihu.com/p/149176367
Kotlin相关面试题
https://blog.51cto.com/u_16052073/13078680