Android基础总结

发布时间:2026/7/11 12:18:36

Android基础总结 Activity生命周期和四大启动模式详解一、Activity 生命周期Activity 的生命周期由一系列回调方法组成用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机​onCreate()​​​调用时机​Activity 首次创建时调用。​作用​初始化布局setContentView、绑定数据、创建后台线程等。​注意​在此方法中应避免耗时操作。​onStart()​​​调用时机​Activity 可见但未获得焦点例如被对话框覆盖。​作用​恢复UI更新或资源加载。​onResume()​​​调用时机​Activity 进入前台并可与用户交互。​作用​启动动画、传感器监听、高频率更新UI等。​关键点​此时 Activity 位于栈顶。​onPause()​​​调用时机​Activity 失去焦点如弹出对话框或跳转到其他 Activity。​作用​保存临时数据、释放资源如摄像头。​注意​需快速执行否则会影响新 Activity 的启动。​onStop()​​​调用时机​Activity 完全不可见被其他 Activity 覆盖或退出。​作用​停止动画、释放非必要资源。​onDestroy()​​​调用时机​Activity 被销毁用户主动退出或系统回收资源。​作用​清理内存、注销广播等。​onRestart()​​​调用时机​Activity 从停止状态重新回到前台如按返回键返回。​流程​onRestart()→onStart()→onResume()。场景应用场景 1打开新页面​​流程​原 Activity 执行onPause()失去焦点新 Activity 依次执行onCreate()初始化onStart()可见onResume()可交互原 Activity 执行onStop()完全不可见​典型场景​从主页跳转到详情页列表页打开新的商品页​场景 2返回上一个页面​​流程​当前 Activity 执行onPause()上一个 Activity 依次执行onRestart()重新激活onStart()可见onResume()可交互当前 Activity 执行onStop()onDestroy()被销毁​典型场景​提交订单后返回购物车查看图片详情后返回相册​场景 3屏幕旋转​​流程​onPause()→onSaveInstanceState()保存数据onStop()→onDestroy()销毁实例重新创建onCreate()携带保存的数据onStart()onRestoreInstanceState()恢复数据onResume()​开发重点​在onSaveInstanceState()保存编辑框内容/滚动位置避免在旋转时中断网络请求​场景 4被弹窗/来电中断​​场景​​生命周期变化​​恢复顺序​普通对话框onPause()onResume()全屏弹窗/来电onPause()→onStop()onRestart()→onResume()​关键区别​是否完全遮挡决定是否触发onStop()二、四大启动模式Launch ModeAndroid 的四大启动模式核心基于任务栈管理机制实现。系统通过 ActivityManagerServiceAMS维护一个全局的任务栈结构每个任务栈由 TaskRecord 对象表示遵循后进先出的堆栈原则。当启动 Activity 时AMS 会根据不同启动模式的预设规则动态调整任务栈的组成。​standard 模式是最基础的方式。它简单地无条件创建新 Activity 实例并将其压入当前任务栈顶部。这种模式不涉及任何复用判断因此可能在栈中积累多个相同 Activity 实例对内存管理构成压力。系统在处理时直接调用 ActivityStarter 的强制压栈方法整个过程没有任何条件检测。适用场景​​常规页面跳转​如商品详情页、新闻内容页​多实例并行需求​如浏览器标签页、文档编辑页​典型案例​电商应用浏览商品主页 → 商品A页 → 商品B页栈内存在多个不同商品页实例文档应用编辑文件同时打开文档1、文档2返回时可逐个切换​singleTop 模式的核心在于栈顶检查机制。启动时AMS 会立即判断目标 Activity 是否恰好位于当前栈顶。如果匹配成功则直接触发该实例的 onNewIntent() 进行数据刷新完全跳过创建流程若不在栈顶则回退到 standard 模式创建新实例。这种设计特别适合通知栏点击等高频重复启动的场景。适用场景​​避免重复通知​通知栏多次点击跳转同一页​高频操作入口​如刷新按钮、重复提交页面​典型案例​微信消息页面当停留在聊天页A时收到新消息点击通知直接刷新当前页面支付倒计时页用户多次点击“重新支付”按钮复用当前页面更新倒计时​特殊场景​扫二维码页面已打开扫码页时再次触发扫码直接复用而非新建​singleTask 模式采用任务栈重构策略。系统会优先搜索与目标 Activity 的 taskAffinity 匹配的任务栈检测是否存在已有实例。如果找到AMS 会先清除该实例之上的所有 Activity触发它们的 onDestroy将目标实例置于栈顶并调用 onNewIntent()若未找到则新建独立任务栈。这种清除机制有效保障了栈内实例唯一性但处理成本较高。适用场景​​应用主页​如微信主界面、设置首页​登录/授权中转站​确保返回时跳过登录页​典型案例​支付流程结束商品页 → 收银台 → 支付成功页点击“返回首页”清空整个支付栈直达主页社交应用登录若已登录过再次打开APP直接进入主页面而非登录页​singleInstance 模式具有全局隔离特性。该模式强制目标 Activity 独占整个任务栈且栈内不允许其他 Activity 存在。启动时AMS 先全局搜索专属栈若存在则直接提至前台复用若不存在则创建带唯一 ID 的新栈。这种模式实现了跨应用级的隔离在系统低内存回收时可能被独立保留常用于相机、拨号等系统组件。适用场景​​系统级共享组件​相机、通讯录选择器​独立功能模块​如浮窗通话界面​典型案例​系统相机调用应用中启动相机拍照返回时直接回到原应用第三方分享面板微信分享时调起系统分享栈完成后自动销毁​特殊注意​银行应用安全键盘通过独立进程防止密码输入被截屏场景需求​​推荐模式​常规页面跳转允许多实例standard避免栈顶重复如通知点击singleTop应用入口/核心页需清栈singleTask独立系统组件跨进程调用singleInstance通过AndroidManifest.xml或 Intent 标志如FLAG_ACTIVITY_NEW_TASK指定控制 Activity 实例与任务栈Task的关系。onNewIntent()是 Activity 被复用时的数据刷新入口用于处理同一个 Activity 实例被再次启动时的新意图Intent而无需重建页面。​核心作用​3个关键点​复用已有页面​避免重复创建相同 Activity节省内存保持当前页面状态如滚动位置、输入内容​更新数据​protected void onNewIntent(Intent intent) { setIntent(intent); // 必须更新否则getIntent()拿旧数据 refreshUI(intent); // 根据新数据刷新界面 }​特定场景触发​​singleTop​当 Activity 位于栈顶时​singleTask/singleInstance​当 Activity 已存在于栈中时​典型场景​点击通知栏多次打开同一聊天页直接刷新消息从支付结果页返回后再次支付复用页面更新订单全局搜索框重复搜索保留搜索历史记录​记住一个原则​只要看到singleTop/singleTask就要考虑是否需要重写onNewIntent()处理数据刷新启动模式在后台运行时的关键行为解析一、后台启动 Activity 的通用规则​基本行为​当应用在后台时启动新 Activity系统会先将应用带回前台新 Activity 会被添加到当前任务栈中用户按返回键时会回到上一个 Activity​核心影响​应用进程优先级提升到前台进程可能触发系统回收机制低内存时后台进程优先被杀二、后台启动的注意事项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. 最佳实践​后台启动 singleTask 主页​// 清理所有历史栈 Intent intent new Intent(context, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);​避免后台 standard 启动​易导致 OOM内存溢出返回栈混乱​跨进程通信​// 启动独立进程的Activity activity android:process:camera_process/三、各模式后台表现对比表启动模式后台启动特点内存效率适用场景standard持续堆叠新实例低需多实例的普通页面singleTop栈顶复用省资源中通知/消息更新singleTask清理栈内多余页面高应用主页/核心入口singleInstance独立进程不受主应用影响最高相机/电话等系统级功能模式实例数量栈位置典型场景standard多个当前栈普通页面singleTop栈顶唯一当前栈防重复启动通知栏singleTask栈内唯一可指定新栈应用主界面singleInstance全局唯一独占新栈独立功能如相机微信小游戏双图标背后的启动模式解析场景重现点击微信图标启动微信主界面在微信内点击进入小游戏​后台出现两个独立图标​微信主应用图标小游戏独立图标核心启动模式singleInstance​实现原理​!-- 小游戏Activity声明示例 -- activity android:name.GameActivity android:launchModesingleInstance android:taskAffinitycom.tencent.game android:process:game_process /​三大关键机制​​独立进程​android:process:game_process小游戏运行在独立的com.tencent.mm:game_process进程与微信主进程com.tencent.mm完全隔离​效果​系统显示两个独立进程图标​独立任务栈​android:taskAffinitycom.tencent.game android:launchModesingleInstance创建专属任务栈与微信主栈隔离​效果​最近任务显示两个独立任务项游戏退出时直接回到手机桌面不经过微信​跨进程通信​// 微信启动游戏的关键代码 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允许多实例完整启动流程​用户点击小游戏入口​​微信创建子进程​通过startActivity()跨进程启动指定singleInstanceNEW_TASK标志​系统创建资源隔离区​独立内存空间分配专属内存独立渲染线程避免微信主线程卡顿独立任务栈系统记录为独立应用​游戏结束后​游戏进程销毁微信主进程不受影响​返回路径​游戏 → 桌面 (不返回微信)技术优势​性能隔离​游戏占500MB内存不影响微信聊天游戏崩溃不会导致微信闪退# 进程内存占用示例 com.tencent.mm: 300MB # 微信主进程 com.tencent.mm:game: 500MB # 游戏进程​独立生命周期​操作微信主进程游戏进程进入游戏onPause()onCreate()游戏切后台-onPause-onStop关闭游戏onResume()onDestroy()游戏崩溃无影响自动重启​用户体验优化​游戏可独立操作微信后台保持运行小窗口模式双向互动微信浮窗游戏对比其他启动模式启动模式是否分进程是否独立图标适用场景standard❌❌普通页面跳转singleTask❌❌微信钱包singleTop❌❌公众号文章​singleInstance​✅​**✅**​小游戏/视频通话典型应用场景微信/QQ内置小游戏直播平台连麦功能银行App的安全键盘AR扫描模块ContentProvider应用场景​ContentProvider 是 Android 实现应用间安全数据共享基于 URI 和 Binder的核心组件同时通过空实现 Provider 的onCreate()机制实现库的自动初始化。​ContentProvider 的主要应用场景​​a) 应用间共享数据最常见目的​​* **系统功能** Android系统自身提供了大量ContentProvider让应用访问系统数据 * ContactsContract.Contacts (通讯录联系人) * MediaStore.Images.Media (相册图片) * MediaStore.Audio.Media (音频文件) * CalendarContract.Events (日历事件) * CallLog.Calls (通话记录) * Settings.System (系统设置) * **第三方应用** 当你的应用需要向其他应用**提供数据**时如提供用户配置、自定义数据库内容你需要实现自己的ContentProvider并定义相应的authority和URI结构。​b) 同一个应用内的结构化数据访问​* 即使只在应用内部使用ContentProvider也提供了一种**标准化**的方式来访问应用本身的数据库或结构化文件。这有利于统一数据访问逻辑、解耦UI和数据层符合MVC/MVP/MVVM架构思想、并便于以后扩展成跨应用共享仅需添加权限和可能的URI结构调整。​c) 跨进程回调/协调​* 一些复杂的跨应用协作可以通过ContentProvider的query()、insert()等操作来触发。例如应用A通过调用应用B的ContentProvider插入一条特定数据可以作为一种信号通知应用B执行某项操作不过Intent广播和Service是更直接的IPC方式。​d) 应用初始化 - Auto-initialization Providers​* **这是非常关键且容易被问到的点** 你在开发中可能会遇到一些第三方库或Android Jetpack库需要在应用启动Application.onCreate()之前就立即执行初始化。**ContentProvider 是实现这种“自动初始化”的核心机制。** * **原理** 系统会在应用进程启动时**早于**创建 Application 实例并调用其 onCreate() 方法之前先**实例化**并**初始化**调用 onCreate() 方法清单文件中所有在application标签里声明的ContentProvider。 * **库的做法** 一个需要预初始化的库可以在其 SDK 中包含一个**不暴露任何实际数据 URI 的“空” ContentProvider**。 1. 这个 Provider 在清单文件中声明。 2. 它的唯一目的是在其 onCreate() 方法中执行库所需的初始化代码如初始化单例、设置全局配置、数据库设置等。 3. 由于其 onCreate() 调用时机非常早在 Application.onCreate() 之前库就能确保在应用的任何代码运行前完成初始化。 * **常见例子** * **WorkManager ( v2.1):** 使用 WorkManagerInitializer Provider 来自动初始化。 * **Firebase:** FirebaseApp的初始化通常通过Provider如FirebaseInitProvider完成。 * **Google Play Services SDKs** 某些服务可能使用此机制。 * **Mockito / Robolectric 等测试框架** 有时用于注入测试依赖。 * **优势** 开发者只需引入库依赖并配置清单文件通常是自动合并的无需在 Application.onCreate() 中显式调用 initialize() 方法减少了初始化配置遗漏的可能性。 * **注意** 过度使用会略微增加启动时间因为系统需要加载和初始化这些 Provider。应仅用于必要的库初始化。代码示例利用 ContentProvider 实现应用初始化自定义初始化 Provider 实现 (空内容提供者)public class AppInitProvider extends ContentProvider { Override public boolean onCreate() { // 系统在 Application.onCreate() 前调用 initializeApp(); return true; // 初始化成功 } private void initializeApp() { // 1. 初始化单例配置 AppConfig.initialize(getContext()); // 2. 设置全局异常处理 Thread.setDefaultUncaughtExceptionHandler(new AppCrashHandler()); // 3. 初始化网络请求库 OkHttpClient client new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .build(); RetrofitManager.init(client); // 4. 初始化数据库框架 Room.databaseBuilder( getContext(), AppDatabase.class, app-db ).fallbackToDestructiveMigration().build(); // 5. 三方库初始化 (示例) FirebaseApp.initializeApp(getContext()); } // 空方法 - 此 Provider 不提供实际数据 Nullable Override public Cursor query(...) { return null; } Nullable Override public Uri insert(...) { return null; } Override public int delete(...) { return 0; } Override public int update(...) { return 0; } Nullable Override public String getType(Uri uri) { return null; } }AndroidManifest.xml 配置application !-- 系统将优先初始化此 Provider -- provider android:name.init.AppInitProvider android:authorities${applicationId}.appinit !-- 唯一标识符 -- android:exportedfalse !-- 不对外暴露 -- android:initOrder100 !-- 多个 Provider 时指定初始化顺序 -- tools:ignoreExportedContentProvider/ !-- 常规 Application 类 -- activity android:name.MainActivity .../ /applicationApplication 类中的后续初始化public class MyApplication extends Application { Override public void onCreate() { super.onCreate(); // 此时 AppInitProvider 已完成初始化 // 1. 初始化必须依赖前序操作的组件 initializePushNotifications(); // 2. 验证初始化状态 if(!AppConfig.isInitialized()) { throw new RuntimeException(初始化失败! 请检查AppInitProvider); } } private void initializePushNotifications() { // 依赖 AppInitProvider 中初始化的网络库 PushService.setHttpClient(RetrofitManager.getClient()); } }使用此模式后开发者只需添加依赖库​零代码初始化三方库​ - 特别适合SDK开发者。如 Firebase 通过此机制实现完全自动初始化无需在 Application 中调用FirebaseApp.initializeApp()。Service 启动方式与实战场景详解Service是Android执行后台长时操作如音乐播放、网络下载或跨进程通信通过AIDL的核心组件其生命周期由系统管理分为启动状态startService()和绑定状态bindService()8.0系统需结合前台服务或JobScheduler规避后台限制。​一、两种核心启动方式1. startService() 启动方式​本质特点​启动后服务与组件完全解耦​生命周期独立运行​必须显式停止​调用 stopSelf() 或 stopService()​完整生命周期流程​首次启动onCreate()→onStartCommand()后续启动直接触发onStartCommand()停止服务onDestroy()​场景适用​​后台长期任务​如音乐播放、定位追踪​无交互任务​如日志上传、数据同步​跨应用操作​如推送消息处理​实战代码​// 启动下载服务 Intent downloadIntent new Intent(this, DownloadService.class); downloadIntent.putExtra(file_url, https://example.com/file.zip); startService(downloadIntent); // 服务内部停止 public class DownloadService extends Service { Override public int onStartCommand(Intent intent, int flags, int startId) { new Thread(() - { downloadFile(intent.getStringExtra(file_url)); stopSelf(); // 下载完成后自动停止 }).start(); return START_NOT_STICKY; } }2. bindService() 启动方式​本质特点​建立组件与服务的绑定关系​通过 IBinder 接口实现双向通信​绑定解绑自动管理生命周期​完整生命周期流程​首次绑定onCreate()→onBind()通信期间通过 Binder 接口交互所有绑定解除onUnbind()→onDestroy()​场景适用​​实时交互场景​如音乐控制播放/暂停/进度​功能模块解耦​如支付模块服务​跨进程通信(IPC)​​不同应用间的数据交换​实战代码​// 绑定音乐服务 ServiceConnection conn new ServiceConnection() { Override public 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; Override public 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(); } Override public 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); } } Override public 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) { // 构建通知内容包含播放控制按钮 // ... } }关键技术与注意事项​​音频焦点管理​AudioManager audioManager (AudioManager) getSystemService(AUDIO_SERVICE); int result audioManager.requestAudioFocus( focusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);​耳机事件处理​// 注册耳机拔出广播 IntentFilter intentFilter new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY); registerReceiver(noisyReceiver, intentFilter); BroadcastReceiver noisyReceiver new BroadcastReceiver() { Override public void onReceive(Context context, Intent intent) { if(AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) { pausePlayback(); // 耳机拔出时暂停播放 } } };​通知栏控制​通过 MediaStyle 通知样式添加播放控制按钮更新播放进度Android 12支持直接显示播放进度条​播放状态持久化​在 onDestroy() 中保存当前播放位置在 onCreate() 中恢复最后播放位置

相关新闻