Android Activity 跳转机制概述
Android 应用开发中,Activity 之间的跳转是最基础也是最重要的功能之一。Activity 代表了应用程序的一个屏幕,用户通过在不同 Activity 之间切换来完成各种操作任务。本文将深入探讨 Android Activity 跳转的各种实现方法、数据传递方式以及开发中需要注意的关键事项。
"Activity 是 Android 应用的基本构建块,掌握 Activity 之间的跳转机制是每个 Android 开发者的必修课。"
基础跳转实现
显式 Intent 跳转
显式 Intent 是最常用的 Activity 跳转方式,它明确指定了要启动的目标 Activity 类。这种方式适用于应用内部的页面跳转。
// 从 MainActivity 跳转到 SecondActivity
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);在 Kotlin 中,代码更加简洁:
// Kotlin 实现
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
// 或者使用更简洁的写法
startActivity(Intent(this, SecondActivity::class.java))隐式 Intent 跳转
隐式 Intent 不直接指定目标组件,而是通过 Action、Category 和 Data 等属性让系统找到合适的组件来处理。这种方式常用于调用系统功能或跨应用交互。
// 打开网页
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.example.com"));
startActivity(intent);
// 拨打电话
Intent callIntent = new Intent(Intent.ACTION_DIAL);
callIntent.setData(Uri.parse("tel:10086"));
startActivity(callIntent);
// 发送邮件
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("text/plain");
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"example@email.com"});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "邮件主题");
emailIntent.putExtra(Intent.EXTRA_TEXT, "邮件内容");
startActivity(Intent.createChooser(emailIntent, "选择邮件客户端"));数据传递方式
基本数据类型传递
Intent 提供了多种 putExtra 方法来传递基本数据类型:
// 发送数据
Intent intent = new Intent(this, TargetActivity.class);
intent.putExtra("name", "张三");
intent.putExtra("age", 25);
intent.putExtra("isVip", true);
intent.putExtra("score", 98.5f);
startActivity(intent);
// 接收数据
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_target);
Intent intent = getIntent();
String name = intent.getStringExtra("name");
int age = intent.getIntExtra("age", 0); // 第二个参数是默认值
boolean isVip = intent.getBooleanExtra("isVip", false);
float score = intent.getFloatExtra("score", 0.0f);
}Bundle 批量传递
当需要传递大量数据时,使用 Bundle 可以让代码更加整洁:
// 使用 Bundle 发送数据
Intent intent = new Intent(this, TargetActivity.class);
Bundle bundle = new Bundle();
bundle.putString("username", "user123");
bundle.putInt("userId", 10001);
bundle.putStringArray("permissions", new String[]{"read", "write"});
intent.putExtras(bundle);
startActivity(intent);
// 接收 Bundle 数据
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
String username = bundle.getString("username");
int userId = bundle.getInt("userId");
String[] permissions = bundle.getStringArray("permissions");
}对象传递
Serializable 方式
// 实体类实现 Serializable 接口
public class User implements Serializable {
private String name;
private int age;
private String email;
// 构造函 数、getter 和 setter 省略
}
// 传递对象
User user = new User("李四", 30, "lisi@example.com");
Intent intent = new Intent(this, TargetActivity.class);
intent.putExtra("user", user);
startActivity(intent);
// 接收对象
User user = (User) getIntent().getSerializableExtra("user");Parcelable 方式(推荐)
Parcelable 是 Android 特有的序列化接口,性能比 Serializable 更好:
public class Product implements Parcelable {
private String name;
private double price;
private int quantity;
// 构造函数
public Product(String name, double price, int quantity) {
this.name = name;
this.price = price;
this.quantity = quantity;
}
// Parcelable 实现
protected Product(Parcel in) {
name = in.readString();
price = in.readDouble();
quantity = in.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeDouble(price);
dest.writeInt(quantity);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<Product> CREATOR = new Creator<Product>() {
@Override
public Product createFromParcel(Parcel in) {
return new Product(in);
}
@Override
public Product[] newArray(int size) {
return new Product[size];
}
};
}
// 使用 Parcelable 传递对象
Product product = new Product("手机", 2999.99, 1);
intent.putExtra("product", product);
// 接收 Parcelable 对象
Product product = getIntent().getParcelableExtra("product");带返回结果的跳转
使用 startActivityForResult(已废弃)
虽然这个方法在新版本中已被废弃,但在旧项目中仍然广泛使用:
// 启动 Activity 并等待结果
private static final int REQUEST_CODE = 1001;
Intent intent = new Intent(this, SelectActivity.class);
startActivityForResult(intent, REQUEST_CODE);
// 在目标 Activity 中返回结果
Intent resultIntent = new Intent();
resultIntent.putExtra("selected_item", "选中的项目");
setResult(RESULT_OK, resultIntent);
finish();
// 处理返回结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
String selectedItem = data.getStringExtra("selected_item");
// 处理返回的数据
}
}使用 Activity Result API(推荐)
新的 Activity Result API 提供了更加类型安全和简洁的方式:
public class MainActivity extends AppCompatActivity {
// 注册结果回调
private ActivityResultLauncher<Intent> launcher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
if (data != null) {
String selectedValue = data.getStringExtra("result");
// 处理返回的数据
}
}
}
);
// 启动 Activity
private void openSelectActivity() {
Intent intent = new Intent(this, SelectActivity.class);
launcher.launch(intent);
}
}Activity 启动模式
四种启动模式详解
Android 提供了四种 Activity 启动模式,可以在 AndroidManifest.xml 中配置:
<activity
android:name=".MainActivity"
android:launchMode="standard" />1. standard(标准模式)
默认模式,每次启动都会创建新的实例:
2. singleTop(栈顶复用)
如果目标 Activity 已经位于栈顶,则复用该实例:
// 在 singleTop 模式下,如果 Activity 被复用
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
// 处理新的 Intent
handleIntent(intent);
}3. singleTask(栈内复用)
在整个任务栈中只有一个实例,如果已存在则将其上面的 Activity 全部出栈:
<activity
android:name=".HomeActivity"
android:launchMode="singleTask"
android:taskAffinity="com.example.task" />4. singleInstance(单实例)
全局唯一实例,独占一个任务栈:
<activity
android:name=".CallActivity"
android:launchMode="singleInstance" />动态设置启动模式
除了 在 Manifest 中配置,还可以通过 Intent Flags 动态设置:
Intent intent = new Intent(this, TargetActivity.class);
// 相当于 singleTask
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
// 相当于 singleTop
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
// 清除整个任务栈
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);动画过渡效果
系统预设动画
// 启动 Activity 后立即调用
startActivity(intent);
overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);
// 在 finish() 后调用
finish();
overrideP endingTransition(R.anim.slide_in_left, R.anim.slide_out_right);自定义动画
创建动画资源文件:
<!-- res/anim/slide_in_right.xml -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="100%p"
android:toXDelta="0" />
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>
<!-- res/anim/slide_out_left.xml -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="0"
android:toXDelta="-100%p" />
<alpha
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>共享元素动画
实现两个 Activity 之间的共享元素过渡:
// 在布局文件中设置 transitionName
<ImageView
android:id="@+id/imageView"
android:transitionName="shared_image"
... />
// 启动 Activity 时传递共享元素
ImageView imageView = findViewById(R.id.imageView);
Intent intent = new Intent(this, DetailActivity.class);
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(
this, imageView, "shared_image");
startActivity(intent, options.toBundle());注意事项与最佳实践
1. 内存泄漏防范
避免在 Intent 中传递大量数据或大对象:
// 错误示例:传递大图片
Bitmap largeBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.large_image);
intent.putExtra("bitmap", largeBitmap); // 可能导致 TransactionTooLargeException
// 正确做法:传递图片路径或 URI
intent.putExtra("image_path", "/storage/emulated/0/image.jpg");
// 或使用全局单例、数据库、文件等方式传递大数据2. Activity 声明检查
确保所有 Activity 都在 AndroidManifest.xml 中声明:
<manifest ...>
<application ...>
<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
android:name=".SecondActivity"
android:exported="false" />
</application>
</manifest>3. 权限处理
某些隐式 Intent 需要相应权限:
<!-- 拨打电话需要权限 -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<!-- 相机权限 -->
<uses-permission android:name="android.permission.CAMERA" />// 运行时权限检查
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CALL_PHONE},
PERMISSION_REQUEST_CODE);
} else {
// 执行拨打电话操作
makePhoneCall();
}4. 空指针异常防范
始终检查 Intent 和数据的有效性:
// 安全地获取 Intent 数据
Intent intent = getIntent();
if (intent != null && intent.hasExtra("key")) {
String value = intent.getStringExtra("key");
if (value != null) {
// 使用数据
}
}
// 使用 Kotlin 的空安全特性
val value = intent?.getStringExtra("key") ?: "默认值"5. 任务栈管理
合理使用 Intent Flags 管理任务栈:
// 退出应用时清除所有 Activity
public void exitApp() {
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("EXIT", true);
startActivity(intent);
}
// 在 MainActivity 中处理退出逻辑
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getIntent().getBooleanExtra("EXIT", false)) {
finish();
return;
}
// 正常初始化
}