想要进入大厂,首先得明白:成功离不开毅力和决心。无论学历、资历如何,只要你有决心并愿意付出时间,总会看到成果。
但除了这些,学习还需要注重效率。互联网上的免费资料虽多,但筛选、整合和实际应用却需要花费大量时间。而且,自己摸索很容易走弯路、踩坑,而且学习内容也可能不够系统。
对于想要进入大厂的开发者来说,基础知识尤为关键。大厂通常深入考察候选人的基础知识,不仅要求了解,还需要深入掌握。因此,仅仅依靠表面的了解很难在面试中脱颖而出。
1. Activity
启动流程
- 当启动一个新的Activity时,系统会首先调用
onCreate()
方法。 - 接着调用
onStart()
和onResume()
方法,使Activity对用户可见。
onSaveInstanceState() 和 onRestoreInstanceState()
-
onSaveInstanceState()
: 当Activity可能不再存在时(如屏幕旋转、用户导航离开等)被调用,用于保存Activity的状态。 -
onRestoreInstanceState()
: 在Activity的onCreate()
之后被调用,用于恢复之前保存的状态。
启动模式和使用场景
- Standard: 默认模式,每次启动都会创建新的实例。
- SingleTop: 如果Activity实例已经在任务栈的顶部,则不会创建新的实例。
- SingleTask: 创建一个新的任务栈,并在其中启动Activity实例。
- SingleInstance: 创建一个新的任务栈,且只包含一个Activity实例。
生命周期执行顺序
Activity A -> Activity B: A的onPause()
和onStop()
被调用,B的onCreate()
、onStart()
和onResume()
被调用。
按返回键:B的onPause()
和onStop()
被调用,A的onRestart()
、onStart()
和onResume()
被调用。
其他生命周期场景
- 横竖屏切换:当前Activity会被销毁并重新创建。
- 按Home键:
onPause()
和onStop()
被调用。 - 锁屏与解锁屏幕:取决于设备实现,可能仅调用
onPause()
。 - 透明Activity:
onCreate()
、onStart()
和onResume()
正常调用。 - Dialog Theme的Activity:与普通Activity相同。
- 弹出Dialog:不影响Activity的生命周期。
onStart() 和 onResume()、onPause() 和 onStop() 的区别
-
onStart()
: Activity对用户不可见,但已加载。 -
onResume()
: Activity对用户可见,且可以与用户交互。 -
onPause()
: Activity对用户仍可见,但即将变为不可见。 -
onStop()
: Activity不再对用户可见。
传递数据
- Intent: 用于在Activity之间传递数据,大小有限制(约1MB)。
- 解决方案:使用Bundle、Serializable、Parcelable或数据库、文件存储等方式。
onNewIntent()
- 当Activity已存在,并且再次接收到与其相同的Intent时调用。
显示启动和隐式启动
- 显示启动:明确指定要启动的Activity。
- 隐式启动:基于Intent中的action和category来匹配要启动的Activity。
Scheme使用场景
- 用于定义自定义的URI格式,如
myapp://path/data
。
ANR
- 应用程序无响应,通常由于主线程长时间运行导致。
onCreate和onRestoreInstance
-
onCreate()
: 在Activity首次创建时调用。 -
onRestoreInstance()
: 在Activity重新创建后用于恢复状态。
跨App启动Activity
- 使用Intent并设置相应的flag。
Activity任务栈
- 存放Activity实例的栈结构。
Flags
- 如
FLAG_ACTIVITY_NEW_TASK
、FLAG_ACTIVITY_CLEAR_TOP
等。
数据保存与恢复
- 使用Bundle保存和恢复数据。
- 进程被Kill后,数据从Bundle中恢复。
2. Service
生命周期
- 创建、启动、绑定、销毁。
两种启动方式
-
startService()
: 启动Service,即使客户端解绑,Service仍运行。 -
bindService()
: 绑定Service到客户端,当客户端解绑时,Service可能销毁。
通信
- 使用Messenger、AIDL、LocalBinder等方式。
IntentService
- 用于在后台执行异步任务,处理完所有Intent后自动结束。
onStartCommand返回值
-
START_NOT_STICKY
、START_STICKY
、START_REDELIVER_INTENT
。
bindService和startService混合使用
- 可以同时使用,但需要注意生命周期和绑定状态。
3. BroadcastReceiver
分类和使用场景
- 粘性广播、非粘性广播。
- 用于接收系统或其他应用发送的广播。
注册方式
- 动态注册:在代码中注册和注销。
- 静态注册:在AndroidManifest.xml中注册。
原理
- BroadcastReceiver接收来自Intent的广播。
4. ContentProvider
ContentProvider 是 Android 中用于实现数据共享的一种组件,它可以让不同的应用程序之间共享数据。数据通常以表格的形式组织,类似于数据库的表。其他应用程序可以通过 ContentResolver 来查询或修改这些数据。
ContentProvider、ContentResolver、ContentObserver 的关系:
- ContentProvider:提供数据访问的接口。
- ContentResolver:用于从 ContentProvider 中获取和修改数据,它是应用程序与 ContentProvider 之间的桥梁。
- ContentObserver:用于监听ContentProvider中的数据变化,当数据发生变化时,会通知注册的观察者。
ContentProvider 的实现原理:
ContentProvider 的实现主要基于数据库,如 SQLite,来存储和管理数据。当其他应用通过 ContentResolver 访问数据时,ContentProvider 会处理这些请求,如查询、插入、更新和删除数据。
ContentProvider 的优点:
- 数据共享:允许不同的应用程序共享数据。
- 安全性:提供了一套权限控制机制,确保只有具有相应权限的应用程序才能访问数据。
- 统一接口:所有 ContentProvider 都遵循相同的接口规范,使得应用程序能够以一种统一的方式访问不同来源的数据。
Uri (统一资源标识符):
Uri 是用于唯一标识资源(如文件、网页、数据库记录等)的字符串。在 Android 中,Uri 常用于标识 ContentProvider 中的数据。例如,一个 Uri 可能表示一个特定的数据库记录或一组记录。
5. Handler
Handler 的实现原理:
Handler 的工作原理基于 Looper 和 MessageQueue。当一个消息(Message)被发送到 Handler 时,Handler 会将这个消息放入与当前线程关联的 MessageQueue 中。Looper 是一个无限循环,它会不断从 MessageQueue 中取出消息并分发给相应的 Handler 进行处理。
子线程中能否直接创建 Handler:
在子线程中不能直接创建 Handler,因为子线程默认没有 Looper。只有主线程(UI线程)在启动时会自动创建 Looper。如果需要在子线程中使用 Handler,需要先手动为子线程创建 Looper。
主线程的 Looper 第一次调用 loop 方法的时间和类:
主线程的 Looper 在 Android 应用程序启动时由 ActivityThread 类创建,并在主线程的 run 方法中调用 Looper.loop() 方法开始运行。
Handler 导致的内存泄露原因及其解决方案:
Handler 导致的内存泄露通常是因为 Handler 持有 Activity 或其他 Context 的引用,而这个 Handler 又被其他长生命周期的对象(如静态变量、线程等)持有。当 Activity 被销毁时,由于 Handler 仍然持有其引用,导致 Activity 无法被垃圾回收器回收,从而造成内存泄露。
解决方案通常包括:
- 使用静态内部类 + 弱引用(WeakReference):将 Handler 放在一个静态内部类中,并使用弱引用持有 Context,这样即使 Handler 被其他对象持有,也不会阻止 Context 被回收。
- 及时移除回调和消息:确保在 Activity 销毁时,移除所有与 Handler 相关的回调和消息,避免在 Activity 销毁后还尝试访问它。
一个线程可以有几个 Handler、Looper、MessageQueue 对象:
一个线程只能有一个 Looper 和一个 MessageQueue。但是一个线程可以有多个 Handler,因为每个 Handler 都有自己的 Message 队列和回调接口,但它们都共享同一个 Looper 和 MessageQueue。
Message 对象的创建方式及区别:
Message 对象可以通过两种方式创建:直接 new 一个 Message 对象,或者调用 Message.obtain() 方法。直接使用 new 创建 Message 会导致频繁的对象分配和垃圾回收,影响性能。而 Message.obtain() 方法会从 MessagePool(消息池)中复用 Message 对象,减少内存分配和垃圾回收的开销。
Message.obtain() 如何维护消息池:
Message.obtain() 方法会首先从 MessagePool 中获取一个已经被回收的 Message 对象(如果存在的话)。如果没有可用的对象,它会创建一个新的 Message。当一个 Message 被处理完毕后,它的 recycle() 方法会被调用,将 Message 返回到 MessagePool 中供下次使用。
Handler 的发送消息方法:
Handler 有多种发送消息的方法,包括 sendMessage()、sendMessageDelayed()、sendEmptyMessage()、sendEmptyMessageDelayed() 等。这些方法的主要区别在于是否延迟发送消息以及是否携带数据。
post 与 sendMessage 的区别和应用场景:
post() 方法用于在主线程中执行 Runnable 对象,而 sendMessage() 方法用于发送一个 Message 对象到 MessageQueue 中。post() 方法通常用于执行简单的任务,而 sendMessage() 方法更适合于需要传递数据和延迟执行的任务。
handler postDelayed 后消息队列的变化:
当使用 postDelayed() 方法发送一个消息时,这个消息会被放入 MessageQueue 中,并根据指定的延迟时间排序。
目录
第一章 Java方面
- Java基础部分
- Java集合
- Java多线程
- Java虚拟机
第二章 Android方面
- Android四大组件相关
- Android异步任务和消息机制
- Android UI绘制相关
- Android性能调优相关
- Android中的IPC
- Android系统SDK相关
- 第三方框架分析
- 综合技术
- 数据结构方面
- 设计模式
- 计算机网络方面
- Kotlin方面
第三章 音视频开发高频面试题
- 为什么巨大的原始视频可以编码成很小的视频呢?这其中的技术是什么呢?
- 怎么做到直播秒开优化?
- 直方图在图像处理里面最重要的作用是什么?
- 数字图像滤波有哪些方法?
- 图像可以提取的特征有哪些?
- 衡量图像重建好坏的标准有哪些?怎样计算?
第四章 Flutter高频面试题
- Dart部分
- Flutter部分
第五章 算法高频面试题
- 如何高效寻找素数
- 如何运用二分查找算法
- 如何高效解决雨水问题
- 如何去除有序数组的重复元素
- 如何高效进行模幂运算
- 如何寻找最长回文子串
第六章 Andrio Framework方面
- 系统启动流程面试题解析
- Binder面试题解析
- Handler面试题解析
- AMS面试题解析