1. Activity在Android开发中的核心地位
Activity作为Android四大组件之首,是每个Android开发者必须掌握的基础概念。简单来说,Activity就是一个包含用户界面的屏幕窗口,用户通过与之交互完成特定任务。比如微信的聊天窗口是一个Activity,朋友圈页面是另一个Activity。
在Android Studio中创建新项目时,系统会自动生成一个MainActivity,这充分体现了Activity的基础性。根据Google官方文档,Activity需要重点关注以下几个核心特性:
- 生命周期管理:从创建到销毁的完整过程控制
- 界面布局:通过XML或代码动态构建用户界面
- Intent通信:Activity之间的跳转和数据传递
- 状态保存:处理配置变更时的数据持久化
提示:理解Activity生命周期是避免内存泄漏和异常崩溃的关键,这也是面试中的高频考点。
2. 创建你的第一个Activity
2.1 基础创建步骤
在Android Studio中手动创建Activity的完整流程如下:
- 右键点击项目包名 → New → Activity → Empty Activity
- 命名Activity类(如SecondActivity)
- 勾选"Generate Layout File"自动创建对应XML布局
- 确认包名位置后点击Finish
系统会自动生成三个关键文件:
- SecondActivity.java:Activity类文件
- activity_second.xml:对应的布局文件
- AndroidManifest.xml:注册新Activity的配置文件
xml复制<!-- AndroidManifest.xml中的典型注册示例 -->
<activity
android:name=".SecondActivity"
android:label="@string/title_activity_second">
</activity>
2.2 布局文件与Activity的绑定
每个Activity都需要关联一个布局文件来定义界面元素。在onCreate()方法中通过setContentView()实现绑定:
java复制@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
// 初始化UI组件
Button myButton = findViewById(R.id.btn_action);
myButton.setOnClickListener(v -> {
// 按钮点击逻辑
});
}
注意:R.layout.xxx是Android资源系统的编译时常量,确保XML文件名与引用名一致。
3. 深入Activity生命周期
3.1 生命周期回调详解
Activity的生命周期由以下核心方法构成:
| 方法 | 触发时机 | 典型用途 |
|---|---|---|
| onCreate() | Activity首次创建时 | 初始化布局和持久数据 |
| onStart() | Activity可见时 | 恢复UI更新 |
| onResume() | 获得用户焦点时 | 启动动画/传感器 |
| onPause() | 失去用户焦点时 | 保存临时数据 |
| onStop() | 完全不可见时 | 释放大内存对象 |
| onDestroy() | 被销毁前 | 清理所有资源 |
完整生命周期图示如下:
code复制onCreate() → onStart() → onResume() → 运行中 → onPause() → onStop() → onDestroy()
3.2 实际场景中的生命周期变化
屏幕旋转场景:
- 当前Activity:onPause() → onStop() → onDestroy()
- 新Activity:onCreate() → onStart() → onResume()
按Home键场景:
onPause() → onStop()
从后台返回场景:
onRestart() → onStart() → onResume()
经验:在onPause()中保存关键数据是最安全的,因为onStop()可能不会被执行(如系统资源紧张时直接杀死进程)。
4. Activity间的跳转与通信
4.1 显式Intent跳转
最基本的Activity跳转方式:
java复制Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
带参数的跳转:
java复制intent.putExtra("username", "JohnDoe");
intent.putExtra("login_time", System.currentTimeMillis());
startActivity(intent);
在目标Activity中获取数据:
java复制String username = getIntent().getStringExtra("username");
long time = getIntent().getLongExtra("login_time", 0L);
4.2 隐式Intent的应用
通过定义action和category实现解耦跳转:
xml复制<!-- AndroidManifest.xml -->
<activity android:name=".ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
调用代码:
java复制Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.setType("text/plain");
sendIntent.putExtra(Intent.EXTRA_TEXT, "分享内容");
startActivity(sendIntent);
4.3 返回结果的处理
启动Activity并期待返回结果:
java复制startActivityForResult(intent, REQUEST_CODE);
在目标Activity中设置返回数据:
java复制Intent resultIntent = new Intent();
resultIntent.putExtra("selection", selectedItem);
setResult(RESULT_OK, resultIntent);
finish();
在原始Activity中接收结果:
java复制@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
String selected = data.getStringExtra("selection");
// 处理返回数据
}
}
5. 实战中的常见问题与解决方案
5.1 内存泄漏预防
典型泄漏场景:
- 静态变量持有Activity引用
- 非静态内部类(如Handler)隐式持有外部类引用
- 未取消的异步任务(如RxJava订阅)
解决方案:
java复制// 使用WeakReference
private static class MyHandler extends Handler {
private final WeakReference<Activity> mActivity;
MyHandler(Activity activity) {
mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
Activity activity = mActivity.get();
if (activity != null) {
// 更新UI
}
}
}
5.2 状态保存与恢复
处理配置变更(如屏幕旋转):
java复制@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("edit_text", mEditText.getText().toString());
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
String text = savedInstanceState.getString("edit_text");
mEditText.setText(text);
}
5.3 启动模式(Launch Mode)的合理使用
AndroidManifest中配置:
xml复制<activity
android:name=".DetailActivity"
android:launchMode="singleTop">
</activity>
四种启动模式对比:
| 模式 | 行为特点 | 适用场景 |
|---|---|---|
| standard | 默认模式,每次新建实例 | 普通页面 |
| singleTop | 栈顶复用 | 通知跳转页 |
| singleTask | 栈内复用并清除其上Activity | 主界面 |
| singleInstance | 独立任务栈 | 系统分享页 |
6. 高级技巧与性能优化
6.1 ViewModel替代传统状态保存
引入Lifecycle组件:
gradle复制implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
创建ViewModel类:
java复制public class UserViewModel extends ViewModel {
private final MutableLiveData<String> username = new MutableLiveData<>();
public void setUsername(String name) {
username.setValue(name);
}
public LiveData<String> getUsername() {
return username;
}
}
在Activity中使用:
java复制UserViewModel model = new ViewModelProvider(this).get(UserViewModel.class);
model.getUsername().observe(this, name -> {
// 更新UI
});
6.2 使用SavedStateHandle处理进程死亡
增强版ViewModel:
java复制public class SavedStateViewModel extends ViewModel {
private final SavedStateHandle savedStateHandle;
public SavedStateViewModel(SavedStateHandle savedStateHandle) {
this.savedStateHandle = savedStateHandle;
}
public void saveData(String key, Object value) {
savedStateHandle.set(key, value);
}
public <T> T getData(String key) {
return savedStateHandle.get(key);
}
}
6.3 Activity结果API的现代化改造
替代startActivityForResult的新方式:
java复制// 注册结果回调
ActivityResultLauncher<Intent> launcher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
Intent data = result.getData();
// 处理结果
}
});
// 启动Activity
launcher.launch(new Intent(this, TargetActivity.class));
7. 调试与问题排查技巧
7.1 生命周期日志打印
基础调试方法:
java复制@Override
protected void onStart() {
super.onStart();
Log.d("Lifecycle", "onStart: " + getLocalClassName());
}
使用LifecycleObserver自动打印:
java复制public class LifecycleLogger implements LifecycleObserver {
private final String TAG;
public LifecycleLogger(String tag) {
this.TAG = tag;
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onCreate() {
Log.d(TAG, "onCreate");
}
// 其他生命周期方法...
}
// 在Activity中添加观察者
getLifecycle().addObserver(new LifecycleLogger("MainActivity"));
7.2 检测内存泄漏
使用Android Profiler:
- 点击Android Studio底部的Profiler选项卡
- 选择Memory视图
- 记录操作前后的内存快照
- 对比分析Activity实例数量
LeakCanary集成:
gradle复制debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
7.3 常见崩溃场景处理
案例1:NullPointerException
java复制// 错误写法
String text = getIntent().getStringExtra("key").toUpperCase();
// 正确写法
String text = "";
if (getIntent().hasExtra("key")) {
text = getIntent().getStringExtra("key");
if (text != null) {
text = text.toUpperCase();
}
}
案例2:Configuration Change导致UI异常
java复制// 在onCreate中检查保存的状态
if (savedInstanceState != null) {
mEditText.setText(savedInstanceState.getString("edit_text"));
}
// 或者直接禁止配置变更
// AndroidManifest.xml
<activity
android:name=".MyActivity"
android:configChanges="orientation|screenSize">
</activity>
8. 现代Android开发中的Activity演进
8.1 从Activity到Compose
Jetpack Compose的声明式UI:
kotlin复制class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
Surface {
Greeting("Android")
}
}
}
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
8.2 单Activity架构的兴起
使用Navigation组件实现单Activity多Fragment:
xml复制<!-- nav_graph.xml -->
<navigation>
<fragment
android:id="@+id/mainFragment"
android:name="com.example.MainFragment"
android:label="Main">
<action
android:id="@+id/toDetail"
app:destination="@id/detailFragment" />
</fragment>
<fragment
android:id="@+id/detailFragment"
android:name="com.example.DetailFragment"
android:label="Detail" />
</navigation>
8.3 Activity与Window的关系剖析
深入理解Window机制:
java复制// 获取Window对象
Window window = getWindow();
// 设置状态栏颜色
window.setStatusBarColor(Color.BLUE);
// 添加系统UI可见性监听
window.getDecorView().setOnSystemUiVisibilityChangeListener(visibility -> {
// 处理系统UI变化
});
在Android开发实践中,我发现正确处理Activity的生命周期和内存管理是保证应用稳定性的基础。特别是在处理耗时操作时,一定要考虑Activity可能已经被销毁的情况。建议结合ViewModel和LiveData来构建更健壮的UI逻辑,这样既能保证数据在配置变更时不丢失,又能避免常见的内存泄漏问题
