当前位置: 首页 > news >正文

Android第十三次面试总结基础

Activity生命周期和四大启动模式详解

一、Activity 生命周期

Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机:

  1. onCreate()​

    • 调用时机​:Activity 首次创建时调用。
    • 作用​:初始化布局(setContentView)、绑定数据、创建后台线程等。
    • 注意​:在此方法中应避免耗时操作。
  2. onStart()​

    • 调用时机​:Activity 可见但未获得焦点(例如被对话框覆盖)。
    • 作用​:恢复UI更新或资源加载。
  3. onResume()​

    • 调用时机​:Activity 进入前台并可与用户交互。
    • 作用​:启动动画、传感器监听、高频率更新UI等。
    • 关键点​:此时 Activity 位于栈顶。
  4. onPause()​

    • 调用时机​:Activity 失去焦点(如弹出对话框或跳转到其他 Activity)。
    • 作用​:保存临时数据、释放资源(如摄像头)。
    • 注意​:需快速执行,否则会影响新 Activity 的启动。
  5. onStop()​

    • 调用时机​:Activity 完全不可见(被其他 Activity 覆盖或退出)。
    • 作用​:停止动画、释放非必要资源。
  6. onDestroy()​

    • 调用时机​:Activity 被销毁(用户主动退出或系统回收资源)。
    • 作用​:清理内存、注销广播等。
  7. onRestart()​

    • 调用时机​:Activity 从停止状态重新回到前台(如按返回键返回)。
    • 流程​:onRestart()onStart()onResume()

场景应用

场景 1:打开新页面

流程​:

  1. 原 Activity 执行 onPause()(失去焦点)
  2. 新 Activity 依次执行:
    • onCreate()(初始化)
    • onStart()(可见)
    • onResume()(可交互)
  3. 原 Activity 执行 onStop()(完全不可见)

典型场景​:

  • 从主页跳转到详情页
  • 列表页打开新的商品页

场景 2:返回上一个页面

流程​:

  1. 当前 Activity 执行 onPause()
  2. 上一个 Activity 依次执行:
    • onRestart()(重新激活)
    • onStart()(可见)
    • onResume()(可交互)
  3. 当前 Activity 执行:
    • onStop()
    • onDestroy()(被销毁)

典型场景​:

  • 提交订单后返回购物车
  • 查看图片详情后返回相册

场景 3:屏幕旋转

流程​:

  1. onPause() → onSaveInstanceState()(保存数据)
  2. onStop() → onDestroy()(销毁实例)
  3. 重新创建:
    • onCreate()(携带保存的数据)
    • onStart()
    • onRestoreInstanceState()(恢复数据)
    • onResume()

开发重点​:

  • 在 onSaveInstanceState() 保存编辑框内容/滚动位置
  • 避免在旋转时中断网络请求

场景 4:被弹窗/来电中断
场景生命周期变化恢复顺序
普通对话框onPause()onResume()
全屏弹窗/来电onPause() → onStop()onRestart() → onResume()

关键区别​:

  • 是否完全遮挡决定是否触发 onStop()


二、四大启动模式(Launch Mode)

通过 AndroidManifest.xml 或 Intent 标志(如 FLAG_ACTIVITY_NEW_TASK)指定,控制 Activity 实例与任务栈(Task)的关系。

  1. standard(默认模式)​

    • 行为​:每次启动创建新实例,无论是否已存在。
    • 示例​:A → B (standard) → B (standard),栈内为 A-B-B。
    • 注意​:可能导致栈中重复实例。
  2. singleTop(栈顶复用)​

    • 行为​:若目标 Activity 位于栈顶,直接复用(调用 onNewIntent());否则创建新实例。
    • 用例​:避免重复通知(如点击通知栏打开同一页面)。
    • 示例​:栈 A-B,启动 B (singleTop) 会复用;启动 C (singleTop) 则新建。
  3. singleTask(栈内单例)​

    • 行为​:在栈中只保留一个实例。若存在则复用(清除其上所有 Activity,调用 onNewIntent());否则新建。
    • 任务栈​:默认在声明时通过 taskAffinity 指定独立栈。
    • 用例​:应用主页(如微信主界面,保证唯一性)。
    • 示例​:栈 A-B-C,启动 B (singleTask) 会清除 C,栈变为 A-B。
  4. singleInstance(全局单例)​

    • 行为​:独占一个任务栈,且栈内仅此一个 Activity。
    • 用例​:独立应用调用(如系统拨号界面)。
    • 示例​:栈1: A-B,启动 C (singleInstance) 会新建栈2: C。返回时先回到栈1。

onNewIntent() 是 Activity 被复用时的数据刷新入口,用于处理同一个 Activity 实例被再次启动时的新意图(Intent),而无需重建页面。

核心作用​(3个关键点):

  1. 复用已有页面

    • 避免重复创建相同 Activity(节省内存)
    • 保持当前页面状态(如滚动位置、输入内容)
  2. 更新数据

    protected void onNewIntent(Intent intent) {setIntent(intent); // 必须更新!否则getIntent()拿旧数据refreshUI(intent); // 根据新数据刷新界面
    }
  3. 特定场景触发

    • singleTop​:当 Activity 位于栈顶时
    • singleTask/singleInstance​:当 Activity 已存在于栈中时

典型场景​:

  • 点击通知栏多次打开同一聊天页(直接刷新消息)
  • 从支付结果页返回后再次支付(复用页面更新订单)
  • 全局搜索框重复搜索(保留搜索历史记录)

记住一个原则​:
只要看到 singleTop/singleTask,就要考虑是否需要重写 onNewIntent() 处理数据刷新!


启动模式在后台运行时的关键行为解析

一、后台启动 Activity 的通用规则
  1. 基本行为​:

    • 当应用在后台时启动新 Activity,系统会先将应用带回前台
    • 新 Activity 会被添加到当前任务栈中
    • 用户按返回键时会回到上一个 Activity
  2. 核心影响​:

    • 应用进程优先级提升到前台进程
    • 可能触发系统回收机制(低内存时后台进程优先被杀)

二、四大启动模式在后台的表现

1. ​standard(默认模式)​

后台启动行为​:

  • 每次启动都会创建新实例
  • 新实例直接入栈,位于原栈顶之上
  • 内存影响​:可能导致栈内多个相同实例,增加内存压力

典型场景​:

// 后台服务收到新消息时启动
Intent intent = new Intent(context, ChatActivity.class);
intent.putExtra("msg_id", newMsgId);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

结果​:

  • 栈内可能出现:Main → Chat(1) → Chat(2) → Chat(3)
  • 内存不足时可能被整体回收

2. ​singleTop(栈顶复用)​

后台启动行为​:

  • 若目标 Activity ​已在栈顶​:触发 onNewIntent() 但不创建新实例
  • 不在栈顶​:创建新实例入栈
  • 省内存优势​:避免栈顶重复创建

典型场景​:

// 后台收到多条通知时
protected void onNewIntent(Intent intent) {// 更新当前聊天页面数据showNewMessage(intent.getStringExtra("new_msg"));
}

实际效果​:

  • 用户正在聊天页:刷新当前页面
  • 用户在其它页:新建聊天页

3. ​singleTask(栈内单例)​

后台启动行为​:

  1. 查找是否存在目标 Activity 的任务栈
  2. 若存在:
    • 清除该实例之上的所有 Activity
    • 触发 onNewIntent()
    • 整个任务栈移到前台
  3. 若不存在:创建新任务栈

内存管理优势​:

  • 自动清理栈内多余 Activity
  • 保持单实例节省内存

典型场景​:

// 支付完成后跳转回主页
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

后台效果​:

  • 原栈:Login → Product → Checkout
  • 启动后:MainActivity(清除所有支付流程页面)

4. ​singleInstance(全局单例)​

后台启动行为​:

  • 独占任务栈直接带到前台
  • 若已存在:直接显示现有实例(触发 onNewIntent()
  • 跨应用特性​:独立于应用主任务栈

特殊内存管理​:

  • 独立进程空间(通过 android:process 属性)
  • 系统回收时可能单独保留

典型场景​:

// 从后台服务启动相机
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

后台效果​:

  • 相机应用独立运行
  • 拍照完成后返回原应用

三、后台启动的注意事项

1. Android 8.0+ 限制
  • 后台启动限制​:应用在后台时无法随意启动 Activity
  • 解决方案​:
    // 必须使用全屏通知
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID).setContentIntent(pendingIntent) // 用户点击才启动.setFullScreenIntent(pendingIntent, true); // 紧急通知
2. 内存回收策略
启动模式回收优先级恢复难度
standard难(多实例)
singleTop中等
singleTask易(单实例)
singleInstance最低最易
3. 最佳实践
  1. 后台启动 singleTask 主页​:

    // 清理所有历史栈
    Intent intent = new Intent(context, MainActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
  2. 避免后台 standard 启动​:

    • 易导致 OOM(内存溢出)
    • 返回栈混乱
  3. 跨进程通信​:

    // 启动独立进程的Activity
    <activity android:process=":camera_process"/>

四、各模式后台表现对比表

启动模式后台启动特点内存效率适用场景
standard持续堆叠新实例需多实例的普通页面
singleTop栈顶复用省资源通知/消息更新
singleTask清理栈内多余页面应用主页/核心入口
singleInstance独立进程不受主应用影响最高相机/电话等系统级功能
模式实例数量栈位置典型场景
standard多个当前栈普通页面
singleTop栈顶唯一当前栈防重复启动(通知栏)
singleTask栈内唯一可指定新栈应用主界面
singleInstance全局唯一独占新栈独立功能(如相机)

微信小游戏双图标背后的启动模式解析

场景重现:

  1. 点击微信图标启动微信主界面

  2. 在微信内点击进入小游戏

  3. 后台出现两个独立图标​:

    • 微信主应用图标

    • 小游戏独立图标

核心启动模式:singleInstance

实现原理​:

<!-- 小游戏Activity声明示例 -->
<activityandroid:name=".GameActivity"android:launchMode="singleInstance"android:taskAffinity="com.tencent.game"android:process=":game_process" />

三大关键机制​:

  1. 独立进程

    android:process=":game_process"
    • 小游戏运行在独立的 com.tencent.mm:game_process 进程

    • 与微信主进程 com.tencent.mm 完全隔离

    • 效果​:系统显示两个独立进程图标

  2. 独立任务栈

    android:taskAffinity="com.tencent.game"
    android:launchMode="singleInstance"
    • 创建专属任务栈(与微信主栈隔离)

    • 效果​:

      • 最近任务显示两个独立任务项

      • 游戏退出时直接回到手机桌面,不经过微信

  3. 跨进程通信

    // 微信启动游戏的关键代码
    Intent intent = new Intent();
    intent.setComponent(new ComponentName("com.tencent.mm", "com.tencent.mm.plugin.game.GameActivity"));
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
    startActivity(intent);
    • 使用 FLAG_ACTIVITY_MULTIPLE_TASK 允许多实例

完整启动流程:

  1. 用户点击小游戏入口

  2. 微信创建子进程​:

    • 通过 startActivity() 跨进程启动

    • 指定 singleInstance + NEW_TASK 标志

  3. 系统创建资源隔离区​:

    • 独立内存空间(分配专属内存)

    • 独立渲染线程(避免微信主线程卡顿)

    • 独立任务栈(系统记录为独立应用)

  4. 游戏结束后​:

    • 游戏进程销毁

    • 微信主进程不受影响

    • 返回路径​:游戏 → 桌面 (不返回微信)

技术优势:

  1. 性能隔离​:

    • 游戏占500MB内存不影响微信聊天

    • 游戏崩溃不会导致微信闪退

    # 进程内存占用示例
    com.tencent.mm: 300MB   # 微信主进程
    com.tencent.mm:game: 500MB # 游戏进程
  2. 独立生命周期​:

    操作

    微信主进程

    游戏进程

    进入游戏

    onPause()

    onCreate()

    游戏切后台

    -

    onPause->onStop

    关闭游戏

    onResume()

    onDestroy()

    游戏崩溃

    无影响

    自动重启

  3. 用户体验优化​:

    • 游戏可独立操作(微信后台保持运行)

    • 小窗口模式双向互动(微信浮窗+游戏)

对比其他启动模式:

启动模式

是否分进程

是否独立图标

适用场景

standard

普通页面跳转

singleTask

微信钱包

singleTop

公众号文章

singleInstance

​**✅**​

小游戏/视频通话

典型应用场景:

  1. 微信/QQ内置小游戏

  2. 直播平台连麦功能

  3. 银行App的安全键盘

  4. AR扫描模块

ContentProvider

一、本质:​数据网关 + 跨进程通信中介

ContentProvider 的核心是 ​数据访问的抽象层,其本质包含双重角色:

  1. 数据网关 (Data Gateway)​

    • 提供统一的数据访问接口(CRUD)
    • 隐藏底层存储实现(SQLite/文件/网络)
    • 通过 URI 实现数据路由
  2. 跨进程通信中介 (IPC Broker)​

    • 基于 Binder 机制实现进程间通信
    • 将数据请求转发到目标进程
    • 封装跨进程数据传输细节

二、底层运作流程(源码级解析)

注册阶段:系统级路由表构建
// 系统启动时注册 Provider
ActivityThread.handleBindApplication() {// 1. 反射创建 Provider 实例ContentProvider provider = clazz.newInstance();// 2. 绑定 Context 并初始化provider.attachInfo(context, providerInfo);// 3. 加入全局路由表 (ActivityManagerService)ActivityManagerService.publishContentProviders() {mProviderMap.put(authority, provider); // 存入路由表}
}
  • 关键数据结构​:mProviderMap(系统服务中的全局哈希表)
  • ​:Authority(如 com.example.provider
  • ​:ContentProvider 实例的 Binder 代理对象

Service 启动方式与实战场景详解

一、两种核心启动方式
1. startService() 启动方式

本质特点​:

  • 启动后服务与组件完全解耦
  • 生命周期独立运行
  • 必须显式停止​(调用 stopSelf() 或 stopService())

完整生命周期流程​:

  1. 首次启动:onCreate() → onStartCommand()
  2. 后续启动:直接触发 onStartCommand()
  3. 停止服务:onDestroy()

场景适用​:

  • 后台长期任务​:如音乐播放、定位追踪
  • 无交互任务​:如日志上传、数据同步
  • 跨应用操作​:如推送消息处理

实战代码​:

// 启动下载服务
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.putExtra("file_url", "https://example.com/file.zip");
startService(downloadIntent);// 服务内部停止
public class DownloadService extends Service {@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {new Thread(() -> {downloadFile(intent.getStringExtra("file_url"));stopSelf();  // 下载完成后自动停止}).start();return START_NOT_STICKY;}
}
2. bindService() 启动方式

本质特点​:

  • 建立组件与服务的绑定关系
  • 通过 IBinder 接口实现双向通信
  • 绑定解绑自动管理生命周期

完整生命周期流程​:

  1. 首次绑定:onCreate() → onBind()
  2. 通信期间:通过 Binder 接口交互
  3. 所有绑定解除:onUnbind() → onDestroy()

场景适用​:

  • 实时交互场景​:如音乐控制(播放/暂停/进度)
  • 功能模块解耦​:如支付模块服务
  • 跨进程通信(IPC)​​:不同应用间的数据交换

实战代码​:

// 绑定音乐服务
ServiceConnection conn = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder binder) {MusicService.MusicBinder musicBinder = (MusicService.MusicBinder) binder;musicBinder.play();  // 直接调用服务方法}
};
bindService(new Intent(this, MusicService.class), conn, BIND_AUTO_CREATE);// 解绑服务
unbindService(conn);

Service使用场景

音乐/视频播放服务

核心实现方案​:

public class MediaPlaybackService extends Service implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener {private MediaPlayer mediaPlayer;private MediaSession mediaSession;private static final int NOTIFICATION_ID = 101;@Overridepublic void onCreate() {// 初始化媒体播放器mediaPlayer = new MediaPlayer();mediaPlayer.setAudioAttributes(new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build());// 创建媒体会话(支持锁屏控制)mediaSession = new MediaSession(this, "MediaPlaybackService");mediaSession.setCallback(new MediaSessionCallback());mediaSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);// 设置通知通道(Android 8.0+必须)createNotificationChannel();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {String action = intent.getStringExtra("action");if("PLAY".equals(action)) {String mediaUrl = intent.getStringExtra("media_url");playMedia(mediaUrl);} else if("PAUSE".equals(action)) {pausePlayback();}return START_NOT_STICKY;}private void playMedia(String mediaUrl) {try {// 停止当前播放if (mediaPlayer.isPlaying()) {mediaPlayer.stop();}mediaPlayer.reset();mediaPlayer.setDataSource(mediaUrl);mediaPlayer.prepareAsync(); // 异步准备播放mediaPlayer.setOnPreparedListener(this);// 转换为前台服务Notification notification = buildMediaNotification("正在播放");startForeground(NOTIFICATION_ID, notification);} catch (IOException e) {Log.e("MediaService", "播放初始化失败", e);}}@Overridepublic void onPrepared(MediaPlayer mp) {mediaPlayer.start();mediaSession.setActive(true);// 更新通知显示播放状态Notification notification = buildMediaNotification("正在播放");NotificationManager nm = getSystemService(NotificationManager.class);nm.notify(NOTIFICATION_ID, notification);}// 构建媒体通知(含播放控制按钮)private Notification buildMediaNotification(String status) {// 构建通知内容(包含播放控制按钮)// ...}
}

关键技术与注意事项​:

  1. 音频焦点管理​:
AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(focusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
  1. 耳机事件处理​:
// 注册耳机拔出广播
IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
registerReceiver(noisyReceiver, intentFilter);BroadcastReceiver noisyReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {if(AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {pausePlayback(); // 耳机拔出时暂停播放}}
};
  1. 通知栏控制​:
  • 通过 MediaStyle 通知样式添加播放控制按钮
  • 更新播放进度(Android 12+支持直接显示播放进度条)
  1. 播放状态持久化​:
  • 在 onDestroy() 中保存当前播放位置
  • 在 onCreate() 中恢复最后播放位置
http://www.xdnf.cn/news/908929.html

相关文章:

  • 【工具变量】上市公司企业华证esg数据集(2009-2024年)
  • 在Window上安装和配置VTK9.x,并在QT项目中调试VTK是否可用
  • 2025远离Deno和Fresh
  • 5G 核心网中 NF 选择机制:基于优先级、权重与负载分担的策略解析
  • 靶场(十九)--靶场体会小白分享--Billyboss
  • Langgraph实战--在Agent中加入人工反馈
  • OLED(SSD306)移植全解-基于IIC
  • 零基础完成 Token 创建的全流程教学
  • 芋道源码 - 本地文件上传配置与实现
  • 【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
  • 配置sudo免密却不生效的问题
  • 【图论 强连通分量】P1653 [USACO04DEC] Cow Ski Area G|普及+
  • for(;;) 和while(1) 的无限循环用法对比,优缺点说明
  • PHP:Web 开发的强大基石与未来展望
  • 给网站添加live2d看板娘
  • 当主观认知遇上机器逻辑:减少大模型工程化中的“主观性”模糊
  • WHAT - script type=“module“
  • 通过Spring AI框架搭建mcp服务端说明
  • 【Block总结】DBlock,结合膨胀空间注意模块(Di-SpAM)和频域模块Gated-FFN|即插即用|CVPR2025
  • FineReport模板认证找不到模板
  • pyarmor加密python程序
  • 【DAY41】简单CNN
  • 深入浅出Java ParallelStream:高效并行利器还是隐藏的陷阱?
  • 【使用conda】安装pytorch
  • python:基于pyside6的桌宠源码分享
  • java面试场景提题:
  • 全球知名具身智能/AI机器人实验室介绍之AI FACTORY基于慕尼黑工业大学
  • 数字孪生:如同为现实世界打造的“克隆体”,解锁无限可能
  • RabbitMQ 队列模式
  • CRM管理软件的审批流程设计与优化:提升企业运营效率的关键策略