Android?Activity!!!
安卓开发必懂:Activity 从入门到实战,彻底搞懂页面交互的核心
一、先搞懂:什么是 Activity?
官方定义很简洁:Activity 是安卓系统中负责与用户交互的可视化组件,它提供了一个可绘制的窗口,用户通过这个窗口完成点击、输入、滑动等所有操作。简单来说,每一个安卓页面,本质上就是一个 Activity—— 比如微信的聊天页、朋友圈页、设置页,分别对应着不同的 Activity 实例。
但要注意,Activity 并不是孤立存在的:
一个应用通常包含多个 Activity,它们协同工作,构成完整的用户体验(比如从登录页跳转至首页,就是两个 Activity 之间的切换);
Activity 由系统统一管理,而非应用自身控制,系统会根据内存情况、用户操作等动态创建、销毁 Activity,这也是我们要重点关注生命周期的原因;
Activity 可以启动其他应用的 Activity(比如调用系统相机、浏览器),这也是安卓组件化、跨应用交互的核心逻辑之一。
举个通俗的例子:Activity 就像手机里的“窗口”,我们打开微信,相当于打开了一个“微信主窗口”(主 Activity);点击进入聊天,就是打开了一个“聊天窗口”(聊天 Activity);退回主页面,就是关闭“聊天窗口”,回到“主窗口”。每个窗口有自己的状态,也有自己的“生存规则”——这就是我们接下来要讲的生命周期。
二、核心:Activity 生命周期
Activity 的生命周期,就是它从“创建”到“销毁”的整个过程,系统会在不同阶段调用对应的回调方法,我们通过重写这些方法,就能控制 Activity 在不同状态下的行为。这是安卓开发的高频考点,也是避免页面崩溃、数据丢失的关键。
Activity 有 6 个核心回调方法,对应 4 种核心状态,我们结合实际场景,用最通俗的方式讲明白(建议结合流程图记忆,效果更佳)
1. 核心回调方法
onCreate():生命周期的“初始化阶段”,系统首次创建 Activity 时调用,整个生命周期只执行一次。我们通常在这里做初始化操作:加载布局(setContentView)、绑定控件、初始化 ViewModel、设置监听器等。比如打开微信聊天页,onCreate() 会加载聊天界面的布局,初始化消息列表。
onStart():Activity 进入“可见但不可交互”状态时调用。此时 Activity 已经显示在屏幕上,但还没有获得焦点(比如被其他半透明窗口遮挡),用户无法点击、输入。这个方法执行时间很短,通常不需要做复杂操作。
onResume():Activity 进入“可见且可交互”状态时调用,也是我们最常用的方法之一。此时 Activity 处于前台,用户可以正常操作(点击按钮、输入文字),我们可以在这里启动动画、恢复播放视频、刷新数据等。
onPause():Activity 进入“暂停状态”时调用,通常是因为有新的 Activity 覆盖在它上面(比如弹出弹窗、切换到其他页面)。此时 Activity 仍可见,但不可交互,我们需要在这里做“轻量清理”:暂停动画、停止视频播放、保存临时数据(比如输入框的内容),避免消耗过多系统资源。
onStop():Activity 进入“停止状态”时调用,此时 Activity 完全被其他 Activity 覆盖,不可见。系统可能会为了释放内存,销毁这个 Activity,因此我们需要在这里做“重量级清理”:关闭网络连接、释放数据库资源、取消广播注册等。
onDestroy():生命周期的“销毁阶段”,系统销毁 Activity 前调用,整个生命周期只执行一次。我们在这里做最终的资源释放:销毁控件引用、取消异步任务、释放内存,避免内存泄漏。
2. 关键生命周期场景
光记方法不够,结合实际场景才能真正理解:
场景 1:打开应用 → 进入主页面:onCreate() → onStart() → onResume();
场景 2:从主页面切换到设置页:主页面 onPause() → 设置页 onCreate() → onStart() → onResume() → 主页面 onStop();
场景 3:从设置页退回主页面:设置页 onPause() → 主页面 onRestart() → onStart() → onResume() → 设置页 onStop() → onDestroy();
场景 4:按Home键退回桌面:当前 Activity onPause() → onStop();再次打开应用:onRestart() → onStart() → onResume();
场景 5:屏幕旋转(比如从竖屏变横屏):当前 Activity 会被销毁后重新创建,执行流程:onPause() → onStop() → onDestroy() → onCreate() → onStart() → onResume()(这也是为什么旋转屏幕会丢失数据,后面会讲解决方案)。
3. 生命周期避坑点
新手最容易踩的 3 个坑,一定要注意:
不要在 onPause()、onStop() 中做耗时操作(比如网络请求),否则会导致页面切换卡顿,甚至 ANR(应用无响应);
屏幕旋转时,Activity 会重建,若不做数据保存,输入框内容、列表滚动位置等会丢失(解决方案:用 onSaveInstanceState(Bundle outState) 保存数据,在 onCreate() 或 onRestoreInstanceState() 中恢复);
不要在 onDestroy() 中做过于复杂的操作,因为系统可能会直接杀死 Activity 进程,不执行 onDestroy(),导致资源泄漏。
三、实战必备:Activity 启动模式(5种,按需选择)
当我们通过 startActivity() 启动一个 Activity 时,系统会将其放入“返回栈”(Task Stack)中,而启动模式决定了这个 Activity 如何创建、如何放入返回栈,以及如何复用。合理选择启动模式,能避免页面重复创建、返回逻辑混乱等问题,提升应用体验。
安卓提供 5 种启动模式(其中 singleInstancePerTask 是 Android 12+ 新增),我们按“适用场景+核心逻辑”的方式,逐个讲清楚:
1. standard
核心逻辑:每次启动 Activity,都会新建一个实例,不管这个实例是否已经存在,新实例会放入当前返回栈的栈顶。
适用场景:大多数常规页面,比如详情页、设置子页、搜索结果页。例如,从商品列表连续点击不同商品,每次都打开新的详情页,返回时逐个退出,符合用户预期。
代码示例(Manifest 中配置):
<activity android:name=".ui.DetailActivity" android:launchMode="standard"/>易错点:误以为返回时会“合并同类项”,实际上每次启动都是新实例,返回时需要逐个退出。
2. singleTop
核心逻辑:如果要启动的 Activity 已经在返回栈的栈顶,则直接复用,不新建实例,系统会调用 onNewIntent() 方法刷新内容;若不在栈顶,则新建实例。
适用场景:通知点击进入的页面、顶部 Tab 容器、Home 页。例如,点击通知进入消息中心,若消息中心已在栈顶,直接复用并刷新消息,避免重复创建多个消息中心页面。
代码示例(代码中设置 Flags):
startActivity(new Intent(this, HomeActivity.class) .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) .putExtra("tab", "inbox"));易错点:仅栈顶复用时生效,若目标 Activity 在栈内但不在栈顶,仍会新建实例;若想“清掉栈顶到目标 Activity 之间的页面并复用”,需搭配 FLAG_ACTIVITY_CLEAR_TOP 使用。
3. singleTask
核心逻辑:只要要启动的 Activity 在当前返回栈中存在,就直接复用,系统会将该 Activity 之上的所有页面全部清除,让它成为栈顶,并调用 onNewIntent();若不存在,则新建实例作为栈根。
适用场景:应用主页面(MainActivity)、路由中转页、从外部唤起后需回到唯一主页的场景。例如,打开应用后跳转多个页面,再次点击主页图标,清除所有中间页面,回到主页面,避免返回时多次点击才能退出。
代码示例(Manifest 中配置):
<activity android:name=".ui.MainActivity" android:launchMode="singleTask" android:exported="true"/>易错点:二次进入会清除该 Activity 之上的所有页面,不适合需要保留多层历史回退的页面(比如多步骤表单)。
4. singleInstance
核心逻辑:该 Activity 会独占一个返回栈,整个系统中只有一个实例,任何应用启动它,都会复用这个实例,且从它启动其他 Activity 时,新 Activity 会放入另一个返回栈。
适用场景:极少用,仅适合系统级页面,比如来电界面、锁屏器、系统浮层。普通应用几乎不需要使用,否则会导致用户体验割裂(比如切换页面时,返回栈跳转混乱)。
四、基础实战:Activity 的基本使用步骤
了解了核心概念和启动模式,我们用一个简单的案例,快速上手 Activity 的基本使用(以 Java 为例,Kotlin 类似):
1. 新建 Activity
在 Android Studio 中,右键包名 → New → Activity → Empty Views Activity,填写 Activity 名称(比如 MainActivity),勾选“Generate Layout File”,自动生成布局文件(activity_main.xml)。
2. 配置 Manifest(关键!)
所有 Activity 必须在 AndroidManifest.xml 中声明,否则系统无法识别。如果是主 Activity,还需要配置 intent-filter,指定为应用入口:
<manifest ...> <application ...> <!-- 主 Activity 配置 --> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <!-- 其他 Activity 配置 --> <activity android:name=".SecondActivity" android:exported="false"/> </application> </manifest>注意:exported 属性表示该 Activity 是否允许被其他应用启动,主 Activity 需设为 true,其他 Activity 若不对外提供,设为 false 更安全。
3. 编写布局文件
在 activity_main.xml 中,添加一个按钮,用于跳转至 SecondActivity:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"> <Button android:id="@+id/btn_jump" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="跳转至第二个页面"/> </LinearLayout>4. 编写 Activity 逻辑
在 MainActivity 中,绑定按钮,设置点击事件,实现跳转功能;在 SecondActivity 中,实现返回功能:
// MainActivity.java public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 加载布局 setContentView(R.layout.activity_main); // 绑定按钮 Button btnJump = findViewById(R.id.btn_jump); // 设置点击事件,跳转至 SecondActivity btnJump.setOnClickListener(v -> { Intent intent = new Intent(MainActivity.this, SecondActivity.class); // 可选:传递数据 intent.putExtra("name", "Android 开发者"); startActivity(intent); }); } } // SecondActivity.java public class SecondActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); // 接收 MainActivity 传递的数据 Intent intent = getIntent(); String name = intent.getStringExtra("name"); Log.d("SecondActivity", "接收的数据:" + name); // 点击返回按钮,关闭当前 Activity Button btnBack = findViewById(R.id.btn_back); btnBack.setOnClickListener(v -> finish()); // finish() 销毁当前 Activity } }五、高频避坑:新手常犯的 Activity 错误
结合日常开发经验,整理了 4 个新手最容易踩的坑,避开这些,能少走很多弯路:
1. 忘记在 Manifest 中声明 Activity
现象:启动 Activity 时崩溃,报错 “Activity not found”。
解决:所有 Activity 必须在 Manifest 中声明,主 Activity 需配置 intent-filter,非主 Activity 需指定 exported 属性。
2. 屏幕旋转导致数据丢失
现象:旋转屏幕后,输入框内容、列表滚动位置消失,甚至页面崩溃。
解决:使用 onSaveInstanceState() 保存数据,在 onCreate() 或 onRestoreInstanceState() 中恢复:
// 保存数据 @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString("inputContent", editText.getText().toString()); // 保存输入框内容 } // 恢复数据(两种方式二选一) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState != null) { String inputContent = savedInstanceState.getString("inputContent"); editText.setText(inputContent); } } // 或 @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); String inputContent = savedInstanceState.getString("inputContent"); editText.setText(inputContent); }3. 内存泄漏(最常见,危害最大)
现象:应用卡顿、闪退,通过 Profiler 查看发现内存占用持续升高。
常见原因及解决:
Activity 中持有静态变量(比如 static Context context = this),导致 Activity 销毁后无法被回收;解决:避免使用静态 Context,若必须使用,用 getApplicationContext()。
异步任务(AsyncTask)、线程未取消,持有 Activity 引用;解决:在 onDestroy() 中取消异步任务、终止线程。
广播接收器、EventBus 未注销;解决:在 onStop() 或 onDestroy() 中注销。
4. 启动模式选择错误
现象:页面重复创建、返回逻辑混乱(比如点击返回,不是回到上一个页面,而是直接退出应用)。
解决:根据页面场景选择启动模式,记住核心原则:常规页面用 standard,主页用 singleTask,通知入口页用 singleTop,系统级页面用 singleInstance。
六、总结:吃透 Activity,筑牢安卓开发基础
Activity 作为安卓应用的“门面”,是用户交互的核心,也是安卓开发的基础中的基础。总结一下核心要点:
本质:用户与应用交互的可视化窗口,每个页面对应一个 Activity 实例;
核心:生命周期(6个回调方法),掌握不同状态下的操作规范,避免崩溃和数据丢失;
实战:启动模式(5种),按需选择,优化页面跳转逻辑;
避坑:记住 Manifest 声明、数据保存、内存泄漏、启动模式这4个关键点
