1. Activity 的生命周期方法有哪些?调用顺序是什么?
- 回答思路:列举 7 个核心方法并说明其触发场景。
- 回答示例:
- 完整生命周期:
onCreate()
→onStart()
→onResume()
→onPause()
→onStop()
→onDestroy()
。 - 可见但非前台:
onPause()
→onStop()
(若用户离开但未完全退出)。 - 返回前台:
onRestart()
→onStart()
→onResume()
。
- 完整生命周期:
2. 启动新 Activity 时,原 Activity 的生命周期如何变化?
- 回答思路:区分目标 Activity 是否为透明主题。
- 回答示例:
- 非透明主题:原 Activity 执行
onPause()
→onStop()
(进入后台)。 - 透明主题:原 Activity 仅执行
onPause()
(保持部分可见)。 - 目标 Activity:
onCreate()
→onStart()
→onResume()
。
- 非透明主题:原 Activity 执行
3. 按下 Back 键返回时,生命周期如何变化?
- 回答思路:描述返回栈的弹出过程。
- 回答示例:
- 目标 Activity:
onPause()
→onStop()
→onDestroy()
(被销毁)。 - 原 Activity:
onRestart()
→onStart()
→onResume()
(恢复前台)。
- 目标 Activity:
4. 屏幕旋转时,Activity 的生命周期会发生什么变化?如何避免重启?
- 回答思路:解释配置变更的默认行为及解决方案。
- 回答示例:
- 默认行为:Activity 被销毁并重建,调用
onPause()
→onStop()
→onDestroy()
→onCreate()
→onStart()
→onResume()
。 - 避免重启:
- 在 AndroidManifest.xml 中设置:
- 默认行为:Activity 被销毁并重建,调用
<activity android:name=".MainActivity"android:configChanges="orientation|screenSize" />
通过onSaveInstanceState()
保存临时状态,onRestoreInstanceState()
恢复。
5. 当 Activity 被系统回收后重新打开,生命周期如何变化?
- 回答思路:说明低内存场景下的回收机制。
- 回答示例:
- 回收时:Activity 可能仅执行
onPause()
→onStop()
(未执行onDestroy()
)。 - 重新打开:调用
onCreate()
→onStart()
→onResume()
,需通过onSaveInstanceState()
恢复数据。
- 回收时:Activity 可能仅执行
6. Activity 进入后台再回到前台时,生命周期如何变化?
- 回答思路:区分短暂离开和长期后台。
- 回答示例:
- 短暂离开(如按 Home 键):
- 后台:
onPause()
→onStop()
。 - 返回前台:
onRestart()
→onStart()
→onResume()
。
- 后台:
- 长期后台(系统回收):需重新创建 Activity 实例。
- 短暂离开(如按 Home 键):
7. onSaveInstanceState () 和 onRestoreInstanceState () 的作用是什么?
- 回答思路:强调状态保存与恢复的场景。
- 回答示例:
- 调用时机:
onSaveInstanceState()
:在onStop()
或onDestroy()
前调用(非主动销毁时,如用户按 Back 键不会触发)。onRestoreInstanceState()
:在onStart()
之后调用。
- 用途:保存临时数据(如 EditText 内容),不适合保存持久化数据。
- 调用时机:
8. 如何处理 Activity 被回收后的状态恢复?
- 回答思路:结合 ViewModel 和 onSaveInstanceState。
- 回答示例:
- ViewModel:保存与界面相关的业务逻辑数据。
- onSaveInstanceState:保存 UI 状态(如滚动位置)。
- 持久化存储:通过 SharedPreferences 或数据库保存关键数据。
9. 启动模式(launchMode)如何影响生命周期?
- 回答思路:以 singleTask 为例说明栈管理的影响。
- 回答示例:
- singleTask 模式:若 Activity 已存在于栈中,会调用
onNewIntent()
而非重新创建,生命周期回调为onPause()
→onStop()
→onNewIntent()
→onRestart()
→onStart()
→onResume()
。
- singleTask 模式:若 Activity 已存在于栈中,会调用
下列是线程池相关面试题:
1.什么是线程池?为什么要使用线程池?
- 回答思路:先给出线程池的定义,再阐述使用线程池的好处。
- 回答示例:线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建的线程集合中启动这些任务。使用线程池主要有以下好处:
- 降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 提高响应速度:当任务到达时,任务可以不需要等到线程创建就能立即执行。
- 提高线程的可管理性:线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。
2. 线程池的工作原理是什么?
- 回答思路:按照任务提交的顺序,依次说明线程池如何处理任务,包括核心线程、任务队列和最大线程数的关系。
- 回答示例:当向线程池提交一个任务时,线程池的处理流程如下:
- 若线程池中的线程数量少于核心线程数,线程池会立即创建一个新线程来执行该任务。
- 若线程数量达到核心线程数,新任务会被放入任务队列中等待执行。
- 若任务队列已满,且线程数量小于最大线程数,线程池会创建新线程来执行任务。
- 若线程数量达到最大线程数,任务队列也已满,此时会触发饱和策略来处理新任务。
3. 线程池有哪些重要参数?它们的作用分别是什么?
- 回答思路:详细介绍
ThreadPoolExecutor
构造函数中的几个重要参数及其作用。 - 回答示例:在 Java 中,
ThreadPoolExecutor
是常用的线程池实现类,它的构造函数包含以下重要参数:- corePoolSize(核心线程数):线程池中的核心线程数量,当提交的任务数小于核心线程数时,线程池会创建新线程来执行任务。
- maximumPoolSize(最大线程数):线程池允许创建的最大线程数量,当任务队列已满且线程数量小于最大线程数时,会创建新线程来执行任务。
- keepAliveTime(线程存活时间):当线程池中的线程数量超过核心线程数时,多余的空闲线程在等待新任务的最长时间,超过这个时间,线程将被销毁。
- unit(时间单位):
keepAliveTime
的时间单位,如TimeUnit.SECONDS
表示秒。 - workQueue(任务队列):用于存储等待执行的任务的队列,常见的有
ArrayBlockingQueue
、LinkedBlockingQueue
等。 - threadFactory(线程工厂):用于创建线程的工厂,可以自定义线程的名称、优先级等。
- handler(饱和策略):当线程池达到最大线程数且任务队列已满时,处理新任务的策略,常见的有
AbortPolicy
(抛出异常)、CallerRunsPolicy
(调用者线程执行)、DiscardPolicy
(丢弃任务)和DiscardOldestPolicy
(丢弃队列中最老的任务)。
4. 如何合理配置线程池的参数?
- 回答思路:根据不同的业务场景,如 CPU 密集型和 IO 密集型任务,说明如何配置核心线程数和其他参数。
- 回答示例:合理配置线程池参数需要考虑任务的类型和系统资源:
- CPU 密集型任务:这类任务主要消耗 CPU 资源,线程池的核心线程数可以设置为 CPU 核心数 + 1,这样可以充分利用 CPU 资源,避免过多的线程切换开销。例如,在一个 4 核的 CPU 上,核心线程数可以设置为 5。
- IO 密集型任务:这类任务主要等待 IO 操作完成,CPU 利用率较低,核心线程数可以设置得较大,一般为 CPU 核心数的 2 倍。例如,在一个 4 核的 CPU 上,核心线程数可以设置为 8。
- 任务队列:根据任务的性质和数量选择合适的任务队列。如果任务量较小且对响应时间要求较高,可以选择有界队列;如果任务量较大且对响应时间要求不高,可以选择无界队列。
- 饱和策略:根据业务需求选择合适的饱和策略。如果任务不允许丢失,可以选择
CallerRunsPolicy
;如果允许任务丢失,可以选择DiscardPolicy
或DiscardOldestPolicy
。
5. 线程池有哪些常见的饱和策略?
- 回答思路:分别介绍几种常见的饱和策略及其特点。
- 回答示例:常见的饱和策略有以下几种:
- AbortPolicy(默认策略):直接抛出
RejectedExecutionException
异常,拒绝新任务。这种策略适用于对任务执行要求严格,不允许任务丢失的场景。 - CallerRunsPolicy:让提交任务的线程来执行这个任务。这种策略可以减缓新任务的提交速度,适用于对系统资源使用有一定限制的场景。
- DiscardPolicy:直接丢弃新任务,不会抛出任何异常。这种策略适用于对任务执行不做严格要求,允许任务丢失的场景。
- DiscardOldestPolicy:丢弃任务队列中最老的任务,然后尝试重新提交新任务。这种策略适用于对任务执行顺序要求不高的场景。
- AbortPolicy(默认策略):直接抛出
6. 线程池在使用过程中可能会遇到哪些问题?如何解决?
- 回答思路:列举一些常见问题,如线程泄漏、任务堆积等,并给出相应的解决方法。
- 回答示例:线程池在使用过程中可能会遇到以下问题及解决方法:
- 线程泄漏:如果线程池中的线程在执行任务时抛出异常而没有正确处理,可能会导致线程无法正常关闭,从而造成线程泄漏。解决方法是在任务的
run()
方法中捕获所有异常,并进行适当的处理。 - 任务堆积:如果任务提交速度过快,超过了线程池的处理能力,会导致任务队列堆积。可以通过调整线程池的参数,如增加核心线程数、扩大任务队列容量或选择合适的饱和策略来解决。
- 资源耗尽:如果线程池的最大线程数设置过大,可能会导致系统资源耗尽。可以根据系统资源和任务特点合理设置线程池的参数,避免创建过多的线程。
- 线程泄漏:如果线程池中的线程在执行任务时抛出异常而没有正确处理,可能会导致线程无法正常关闭,从而造成线程泄漏。解决方法是在任务的
7. 如何关闭线程池?
- 回答思路:介绍线程池的两种关闭方法及其区别。
- 回答示例:可以使用
shutdown()
和shutdownNow()
方法来关闭线程池:- shutdown():该方法会平滑地关闭线程池,不再接受新任务,但会等待队列中的任务执行完毕。调用该方法后,线程池的状态会变为
SHUTDOWN
。 - shutdownNow():该方法会立即关闭线程池,尝试停止正在执行的任务,并返回队列中未执行的任务列表。调用该方法后,线程池的状态会变为
STOP
。
- shutdown():该方法会平滑地关闭线程池,不再接受新任务,但会等待队列中的任务执行完毕。调用该方法后,线程池的状态会变为
希望这篇文章能给您带来帮助!!!
感谢观看!!!