1. Android Activity基础概念解析
Activity作为Android四大组件之一,是每个Android开发者必须掌握的核心概念。简单来说,Activity就是一个包含用户界面的屏幕窗口,用户可以通过它与应用程序进行交互。比如我们常见的拨打电话、发送短信、浏览网页等功能,都是通过Activity来实现的。
在Android应用中,一个Activity通常对应一个屏幕界面。例如,微信的主界面是一个Activity,聊天窗口是另一个Activity,朋友圈又是一个独立的Activity。这种设计使得Android应用可以灵活地组合不同的功能模块。
重要提示:所有Activity都必须在AndroidManifest.xml文件中声明,否则应用运行时会出现ClassNotFoundException错误导致崩溃。
1.1 Activity的生命周期详解
理解Activity生命周期是开发稳定Android应用的关键。Activity生命周期包含以下几个核心方法:
- onCreate():Activity首次创建时调用,通常在这里完成初始化工作,如设置布局、绑定控件等
- onStart():Activity即将变为可见状态时调用
- onResume():Activity获得用户焦点,可以与用户交互时调用
- onPause():当另一个Activity获得焦点时调用,当前Activity仍部分可见
- onStop():Activity完全不可见时调用
- onDestroy():Activity被销毁前调用
- onRestart():Activity从停止状态重新启动时调用
生命周期方法的调用顺序可以通过以下场景来理解:
- 启动Activity:onCreate → onStart → onResume
- 按Home键返回桌面:onPause → onStop
- 重新打开应用:onRestart → onStart → onResume
- 按返回键退出:onPause → onStop → onDestroy
1.2 Activity的创建与配置
在Android Studio中创建Activity有两种主要方式:
- 继承android.app.Activity类
- 继承android.support.v7.app.AppCompatActivity类(推荐)
AppCompatActivity是Support库提供的兼容性更好的Activity基类,它可以在不同Android版本上提供一致的用户体验。创建Activity的基本步骤如下:
- 新建Java类继承AppCompatActivity
- 重写onCreate方法
- 在onCreate中调用setContentView设置布局文件
- 在AndroidManifest.xml中注册Activity
java复制public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
2. Activity的启动与数据传递
2.1 启动Activity的两种方式
Android中启动Activity主要有显式启动和隐式启动两种方式:
显式启动:明确指定要启动的Activity类
java复制// 最常见的方式
startActivity(new Intent(CurrentActivity.this, TargetActivity.class));
// 通过ComponentName指定
ComponentName cn = new ComponentName("当前包名", "目标Activity全限定名");
Intent intent = new Intent();
intent.setComponent(cn);
startActivity(intent);
隐式启动:通过Intent Filter匹配系统或应用中符合条件的Activity
java复制// 打开网页
Uri uri = Uri.parse("http://www.example.com");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
// 拨打电话
Uri uri = Uri.parse("tel:10086");
Intent intent = new Intent(Intent.ACTION_DIAL, uri);
startActivity(intent);
2.2 Activity间的数据传递
Activity间传递数据主要通过Intent的putExtra方法实现:
发送数据:
java复制Intent intent = new Intent(this, TargetActivity.class);
intent.putExtra("key_string", "这是一个字符串");
intent.putExtra("key_int", 123);
intent.putExtra("key_boolean", true);
startActivity(intent);
接收数据:
java复制@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String str = getIntent().getStringExtra("key_string");
int num = getIntent().getIntExtra("key_int", 0);
boolean flag = getIntent().getBooleanExtra("key_boolean", false);
}
对于复杂对象,可以通过实现Serializable或Parcelable接口来传递。Parcelable是Android特有的序列化方式,性能比Serializable更好。
3. Activity的配置与特殊处理
3.1 横竖屏切换处理
Android设备在横竖屏切换时,默认会销毁当前Activity并重新创建,这可能导致数据丢失。处理方式有以下几种:
- 禁止横竖屏切换:
在AndroidManifest.xml中配置:
xml复制<activity android:name=".MainActivity"
android:screenOrientation="portrait" /> <!-- 固定竖屏 -->
- 保存状态数据:
重写onSaveInstanceState方法保存临时数据:
java复制@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("key", "需要保存的数据");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null) {
String data = savedInstanceState.getString("key");
}
}
- 手动处理配置变更:
在AndroidManifest.xml中声明配置变更由Activity自行处理:
xml复制<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize" />
然后重写onConfigurationChanged方法:
java复制@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// 处理配置变更
}
3.2 Activity的启动模式
Android提供了四种Activity启动模式,通过android:launchMode属性配置:
- standard:默认模式,每次启动都创建新实例
- singleTop:如果Activity已在栈顶,则不会创建新实例
- singleTask:在整个应用中只保留一个实例
- singleInstance:单独存在于一个任务栈中
合理使用启动模式可以优化应用的内存使用和用户体验。
4. 常见系统Activity的使用
Android系统提供了许多内置Activity,可以通过Intent直接调用:
java复制// 打开系统设置
Intent intent = new Intent(Settings.ACTION_SETTINGS);
startActivity(intent);
// 打开相机拍照
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, REQUEST_CODE_CAMERA);
// 选择图片
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, REQUEST_CODE_GALLERY);
// 打开应用商店
Uri uri = Uri.parse("market://details?id=" + getPackageName());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
处理返回结果需要重写onActivityResult方法:
java复制@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case REQUEST_CODE_CAMERA:
// 处理拍照结果
break;
case REQUEST_CODE_GALLERY:
// 处理选图结果
break;
}
}
}
5. Activity开发中的常见问题与解决方案
5.1 内存泄漏问题
Activity是最容易发生内存泄漏的组件之一。常见的内存泄漏场景包括:
- 静态变量持有Activity引用
- 非静态内部类(如Handler)隐式持有外部类引用
- 注册的监听器或广播没有及时取消
解决方案:
- 避免静态变量持有Activity
- 使用静态内部类+弱引用的方式处理Handler
- 在onDestroy中取消注册所有监听器和广播
5.2 数据恢复问题
当Activity因系统资源不足被回收后再次恢复时,如何保证用户体验一致?
最佳实践:
- 使用onSaveInstanceState保存临时数据
- 持久化重要数据到数据库或SharedPreferences
- 使用ViewModel保存UI相关数据
5.3 多窗口模式适配
从Android 7.0开始支持多窗口模式,Activity需要做相应适配:
- 检查当前是否处于多窗口模式:
java复制if (isInMultiWindowMode()) {
// 多窗口模式下的特殊处理
}
- 处理配置变化:
xml复制<activity android:name=".MainActivity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" />
- 重写onMultiWindowModeChanged方法响应模式变化
5.4 深色主题适配
随着Android 10引入深色主题,Activity需要进行主题适配:
- 在res/values/styles.xml中定义主题:
xml复制<style name="AppTheme" parent="Theme.AppCompat.DayNight">
<!-- 主题属性 -->
</style>
- 在Manifest中应用主题:
xml复制<application
android:theme="@style/AppTheme">
</application>
- 动态切换主题:
java复制AppCompatDelegate.setDefaultNightMode(
isNightMode ? MODE_NIGHT_YES : MODE_NIGHT_NO);
recreate(); // 重新创建Activity应用新主题
6. Activity高级技巧与最佳实践
6.1 使用Fragment优化Activity
Fragment可以作为Activity的模块化组成部分,带来以下优势:
- 更好的界面复用:同一Fragment可以在不同Activity中使用
- 更灵活的界面组合:根据屏幕尺寸动态调整Fragment布局
- 更流畅的用户体验:Fragment事务支持动画效果
基本用法:
java复制getSupportFragmentManager().beginTransaction()
.add(R.id.container, new MyFragment())
.commit();
6.2 使用ViewBinding简化代码
ViewBinding可以替代findViewById,使代码更简洁安全:
- 在build.gradle中启用:
groovy复制android {
viewBinding {
enabled = true
}
}
- 在Activity中使用:
java复制private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
binding.textView.setText("Hello ViewBinding");
}
6.3 使用Lifecycle组件管理生命周期
Lifecycle组件可以帮助我们更好地管理Activity生命周期相关的逻辑:
- 添加依赖:
groovy复制implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
- 实现LifecycleObserver:
java复制public class MyObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
// Activity onResume时执行
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
// Activity onPause时执行
}
}
- 在Activity中注册:
java复制getLifecycle().addObserver(new MyObserver());
6.4 优化Activity启动速度
Activity启动速度直接影响用户体验,优化建议包括:
- 减少onCreate中的耗时操作
- 使用SplashActivity预加载资源
- 启用窗口背景优化:
xml复制<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowDisablePreview">false</item>
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
- 使用TraceView分析启动耗时
7. 现代Android开发中的Activity演进
随着Jetpack组件的普及,Activity的角色正在发生变化:
- 职责简化:业务逻辑逐渐迁移到ViewModel中
- 组合替代继承:通过组合各种Lifecycle组件实现功能
- 导航组件:使用Navigation组件管理Fragment导航,减少Activity数量
典型现代Activity结构:
java复制public class MainActivity extends AppCompatActivity {
private MainViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 初始化ViewModel
viewModel = new ViewModelProvider(this).get(MainViewModel.class);
// 观察LiveData
viewModel.getData().observe(this, data -> {
// 更新UI
});
// 设置点击监听
binding.button.setOnClickListener(v -> {
viewModel.loadData();
});
}
}
这种架构使得Activity更加轻量,职责更单一,便于测试和维护。
