在Android开发中,Activity或组件之间的跳转与数据传递几乎每天都会用到。Intent作为消息载体,既可以精确指向某个目标组件,也可以只描述要执行的动作让系统匹配。很多数据传递失败的情况,根源在于创建Intent的方式和读取数据时使用的Key或类型不匹配。本篇文章结合代码示例,分别演示显式Intent和隐式Intent在传值场景下的正确写法与避坑要点。

一、显式Intent跳转传值的核心用法
显式Intent通过指定目标组件的完整类名来创建,通常写法是new Intent(当前Activity.this, 目标Activity.class)。这种方式只适合应用内部跳转,因为类名在编译期已经确定,不存在歧义。它的优点是速度快、指向明确,不会因为系统匹配不到组件而抛出异常。创建Intent之后,可以连续调用putExtra方法写入键值对,支持的数据类型包括String、int、boolean、double、float、long以及对应的数组类型。
写入数据时需要注意Key的命名保持一致。推荐把Key定义为常量,避免在发送端和接收端出现拼写不一致。下面是一个完整示例,从MainActivity跳转到SecondActivity并传递用户名、年龄和登录状态三个字段:
public class MainActivity extends AppCompatActivity {
public static final String KEY_NAME = "user_name";
public static final String KEY_AGE = "user_age";
public static final String KEY_LOGIN = "is_login";
public void goToSecond() {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra(KEY_NAME, "张三");
intent.putExtra(KEY_AGE, 25);
intent.putExtra(KEY_LOGIN, true);
startActivity(intent);
}
}
目标Activity在onCreate方法中通过getIntent()获取源Intent,再调用对应的getXXXExtra方法读取数据。读取类型必须与写入类型完全一致,否则系统会尝试转换,转换失败时抛出ClassCastException。对于数值类型,建议使用带默认值的重载方法,例如getIntExtra(KEY_AGE, 0),这样即使发送端遗漏了该字段,接收端也能拿到一个安全值而不会空指针。
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
String name = getIntent().getStringExtra(MainActivity.KEY_NAME);
int age = getIntent().getIntExtra(MainActivity.KEY_AGE, 0);
boolean isLogin = getIntent().getBooleanExtra(MainActivity.KEY_LOGIN, false);
}
}
如果需要一次性传递多个字段,也可以先把所有数据封装到Bundle对象中,再通过intent.putExtras(bundle)整体写入。接收端使用getIntent().getExtras()获取Bundle,再从中读取各个Key。Bundle内部的Key不会因为多次传递而丢失,适合把参数集中管理。
二、隐式Intent的配置与传值细节
隐式Intent不直接指定目标组件类名,而是通过设置Action、Category、Data等属性来描述意图,由系统根据这些条件匹配满足条件的组件。这种方式适合跨应用调用,例如打开浏览器、发送邮件、分享内容,也可以实现应用内部的组件路由。隐式跳转传值同样使用putExtra,但接收端必须正确配置<intent-filter>,否则系统无法找到目标组件,会抛出ActivityNotFoundException。
配置隐式接收组件时,在AndroidManifest.xml中为Activity声明<intent-filter>,至少包含一个Action,通常还需要DEFAULT类别。如果需要接收Data,还要配置<data>标签,其中的scheme、host、path等属性决定匹配范围。下面配置一个可以接收自定义Action和HTTPS协议数据的Activity:
<activity android:name=".TargetActivity" android:exported="true">
<intent-filter>
<action android:name="com.example.app.SHOW_USER" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="https" android:host="ipipp.com" />
</intent-filter>
</activity>
在发送隐式Intent时,可以只设置Action,也可以设置Data。如果同时设置了Action和Data,接收方必须两者都匹配。下面示例展示如何用隐式Intent跳转到TargetActivity并传递数据:
Intent intent = new Intent();
intent.setAction("com.example.app.SHOW_USER");
intent.setData(Uri.parse("https://ipipp.com/user?id=100"));
intent.putExtra("user_name", "李四");
intent.putExtra("level", 7);
startActivity(intent);
接收端在TargetActivity里读取数据的方式与显式Intent相同,通过getIntent().getStringExtra等方法取值。需要注意的是,如果发送端通过Data中的query参数传递信息,接收端还需要手动解析Uri,例如调用getIntent().getData().getQueryParameter("id"),这和数据区中的Extra是两个独立通道,不要混淆。
隐式跳转存在一个常见风险:设备上可能没有任何组件能够匹配该Intent,导致崩溃。为了避免这个问题,在调用startActivity之前应该使用intent.resolveActivity(getPackageManager())判断结果是否为null。如果为null说明没有可接收组件,可以提示用户或改用其他处理方式。
三、复杂数据的传递与Bundle封装
基本类型的传值简单直观,但实际业务中经常需要传递对象、列表或序列化数据。Android提供了两种主要方式:Serializable和Parcelable。Serializable实现简单,但性能较差,适合传递少量配置数据;Parcelable代码量多一些,但执行效率高,适合在Activity间频繁传递大对象或列表。无论哪种方式,对象类都必须实现对应接口,发送时通过putExtra写入,接收时用getSerializableExtra或getParcelableExtra读取。
下面以Parcelable为例,定义一个User类并实现Parcelable接口,然后通过Intent传递。注意Parcelable要求对象内部成员的类型也必须支持Parcelable或基本类型,否则写入时会报错。示例中User包含name和age两个字段:
public class User implements Parcelable {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
protected User(Parcel in) {
name = in.readString();
age = in.readInt();
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
}
发送端可以使用intent.putExtra("user", user)传递,接收端使用getIntent().getParcelableExtra("user")读取。如果传递ArrayList,可以调用putParcelableArrayListExtra,接收端使用对应的getParcelableArrayListExtra方法。需要注意的是,如果接收端读取类型错误,同样会抛出ClassCastException,因此Key和类型需要双方保持一致。
对于需要同时传递多个对象的场景,建议统一使用Bundle。发送端创建Bundle并写入多个数据,然后intent.putExtras(bundle);接收端先Bundle bundle = getIntent().getExtras();再从中取各个Key。Bundle还可以避免在Intent上反复调用putExtra导致代码臃肿,并且方便在多个组件之间复用同一组参数。
四、跳转传值中的异常排查与最佳实践
Intent传值看似简单,但在实际项目里经常出现取不到数据、类型转换异常、隐式跳转找不到组件等问题。排查时首先确认发送端确实执行了putExtra,并且Key完全一致。一个常见的疏忽是Key在两端一个定义为user_name,另一端却写成username,导致返回默认值或null。建议把Key统一放在一个常量类中,两端引用同一个常量。
第二类问题是类型不匹配。例如发送时写入的是int型,接收时却用getStringExtra读取,系统不会自动把数字转成字符串,而是返回null。如果读取数值时使用了错误的默认值类型,也可能出现转换异常。正确做法是发送和接收使用同一类型,或者在接收端根据业务需要主动调用目标类型的get方法并设置合理的默认值。
第三类问题是隐式Intent没有配置<intent-filter>或忘记设置android:exported。从Android 12开始,带有<intent-filter>的组件必须在manifest中显式声明android:exported,否则应用无法编译通过。对于只供应用内部使用的组件,可以设置android:exported="false"并只使用显式Intent;对于需要被外部调用的组件,设置为true并注意安全校验。
最后,在调用隐式Intent前务必进行resolveActivity判断,防止因没有接收方导致异常。对于返回值场景,旧版的startActivityForResult已经过时,建议使用Activity Result API,通过registerForActivityResult注册回调,再启动Intent。这种方式把结果处理逻辑与启动代码解耦,避免onActivityResult里大量if判断。传值依然是putExtra,返回结果则用setResult和putExtra配合。
总之,显式Intent适合应用内精确跳转,隐式Intent适合灵活路由和跨应用调用,但两者传值机制相同。只要保证Key一致、类型匹配、做好前置校验,就能避免大多数Intent传值异常。
Android Intent显式跳转隐式跳转修改时间:2026-08-25 19:02:09