嘿,各位在代码世界里摸爬滚打的准大神们!今天咱们来聊一个Android开发里既基础又贼重要的话题——多个Activity之间,怎么“呼来唤去”,还得让被叫走的那位“带点东西回来”。
想象一下这个场景:你(主Activity)在家里(主界面)舒舒服服躺着,突然想吃外卖了。这时候你有两个选择:
普通呼叫: 你打开外卖App(启动新Activity),看了一眼,然后直接按Home键溜了(按返回键)。结果就是,你啥也没买,空手而归。这在代码里对应
startActivity(),一别两宽,各自安好。带任务呼叫: 你打开外卖App(启动新Activity),精挑细选,下单付款,然后App告诉你“订单已生成,预计30分钟送达”。最后你返回桌面,但你的手里(或者说,你的记忆里)多了一个“订单号”。这就是我们今天要说的 “调用另一个Activity并返回结果”。
后一种情况,在编程世界里,我们称之为 “启动一个Activity以获得结果”。它就像是派你的小弟(新Activity)出去执行一个任务,任务完成后,他必须回来向你汇报,并且把任务成果(比如一份机密文件、用户的选择、一张拍好的照片)亲手交到你手上。
在你派小弟出门之前,你得告诉他两件事:
你要去哪,干什么? (通过Intent指定目标Activity)我凭什么认定是你回来了? (请求码 Request Code)在我们的外卖比喻里,“打开外卖App”这个动作,就是一个Intent。我们通过
startActivityForResult(intent, requestCode) 这个方法,来启动这次“带结果的旅程”。
requestCode 是个啥?
想象一下,你同时派了小弟A去买奶茶(请求码=1),又派了小弟B去取快递(请求码=2)。过了一会儿,小弟回来了,你光看脸可能记不清是谁,但如果你出门前给他们每人发了个不同颜色的帽子(请求码),你就能立刻分清:哦,戴红帽子(请求码=1)的是买奶茶的,我得问他奶茶买好了没。
这个
requestCode 就是你自定义的一个整数,用来在之后区分是哪个“小弟”回来了。
小弟(新Activity)被启动后,他会独立运行,拥有自己的界面和逻辑。比如,他可能是一个让用户选择联系人的界面,或者是一个拍照界面。
当他的任务完成时(用户选好了联系人,或者拍完了照片),他不能默默地自己关闭就完事了。他需要做两件事:
把任务结果打包。 (准备一个Intent,把数据放进去)设定任务状态。 (是成功完成了,还是用户取消了?)“自杀”并送回结果。 (调用
setResult() 然后
finish())
这里的关键方法是
setResult(int resultCode, Intent data)。
resultCode 又是啥?
它用来告诉老大任务执行的大体情况,通常只有两个预定义的值:
Activity.RESULT_OK:任务圆满完成!这是你想要的。
Activity.RESULT_CANCELED:任务被取消了,用户啥也没干就按返回键溜了。
data 里面放啥?
这就是真正的“特产”了。它是一个Intent对象,你可以通过它的
putExtra() 方法,把任何你想带回去的数据塞进去,比如一个字符串、一个数字、一个对象等等。
小弟(新Activity)的代码模板长这样:
// 当小弟完成任务时(比如用户点击了“确认选择”按钮)
public void onConfirmButtonClick(View view) {
Intent resultIntent = new Intent(); // 创建一个空Intent,专门用来装结果
resultIntent.putExtra("KEY_SELECTED_DATA", "这是带回去的特产!"); // 打包特产
setResult(Activity.RESULT_OK, resultIntent); // 告诉系统:我成功了,这是结果
finish(); // 结束自己,踏上归途
}
// 如果用户啥也不干直接按返回键
@Override
public void onBackPressed() {
setResult(Activity.RESULT_CANCELED); // 告诉系统:任务取消了,没结果
finish(); // 结束自己
}
老大(主Activity)在派小弟出门后,并不会傻等着。它会继续响应其他操作,该干嘛干嘛。但是,它心里一直记着这事儿,并且设立了一个 “专门的接待处”——
onActivityResult(int requestCode, int resultCode, Intent data) 方法。
一旦有任何一个小弟(被它启动的Activity)返回,系统就会自动调用这个“接待处”方法。老大需要在这里做三件事:
看帽子(requestCode): 确认是哪个小弟回来了?是买奶茶的还是取快递的?看脸色(resultCode): 任务成功了还是失败了?接包裹(data): 如果成功了,就拆开包裹(Intent data),拿出里面的特产(数据)。老大(主Activity)的代码模板长这样:
// 启动小弟的代码
private static final int REQUEST_CODE_TAKE_OUT = 1001; // 定义一个独特的请求码
public void onStartTakeOutActivityClick(View view) {
Intent intent = new Intent(this, TakeOutActivity.class); // 创建Intent,指定小弟是谁
startActivityForResult(intent, REQUEST_CODE_TAKE_OUT); // 派小弟出门!
}
// 重写这个“接待处”方法
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); // 这行代码最好一直留着
// 第一步:看帽子,是派出去买外卖的小弟回来了吗?
if (requestCode == REQUEST_CODE_TAKE_OUT) {
// 第二步:看脸色,任务成功了吗?
if (resultCode == Activity.RESULT_OK) {
// 第三步:接包裹,拆特产!
if (data != null) {
String result = data.getStringExtra("KEY_SELECTED_DATA");
// 拿到数据了,更新UI或者做其他逻辑
TextView tvResult = findViewById(R.id.tv_result);
tvResult.setText("外卖点好了!订单是:" + result);
}
} else if (resultCode == Activity.RESULT_CANCELED) {
// 用户取消了,啥也没选
Toast.makeText(this, "用户取消了选择", Toast.LENGTH_SHORT).show();
}
}
// 未来还可以在这里用 else if 判断其他 requestCode,接待别的小弟
}
理论说再多,不如代码跑一跑。下面是一个超级简单的完整示例。
功能: 主页面一个按钮,点击后打开第二个页面,在第二个页面输入一句话,点击确定后,这句话会显示在主页面。
1. activity_main.xml (主页面布局)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<Button
android:id="@+id/btn_go_to_second"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="去第二个页面写句话" />
<TextView
android:id="@+id/tv_message_from_second"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="等待来自第二个页面的消息..."
android:textSize="18sp" />
</LinearLayout>
2. MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE_SECOND_ACTIVITY = 1;
private TextView tvMessage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnGo = findViewById(R.id.btn_go_to_second);
tvMessage = findViewById(R.id.tv_message_from_second);
btnGo.setOnClickListener(v -> {
// 派小弟出门
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivityForResult(intent, REQUEST_CODE_SECOND_ACTIVITY);
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 确认是咱们等的小弟
if (requestCode == REQUEST_CODE_SECOND_ACTIVITY) {
// 看看任务状态
if (resultCode == Activity.RESULT_OK) {
// 拆包裹,拿数据
if (data != null) {
String message = data.getStringExtra("EXTRA_MESSAGE");
tvMessage.setText("第二个页面说: " + message);
}
} else {
tvMessage.setText("对方啥也没说就回来了...");
}
}
}
}
3. activity_second.xml (第二个页面布局)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/et_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="在这里输入你想带回主页的话" />
<Button
android:id="@+id/btn_confirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="确认并返回" />
</LinearLayout>
4. SecondActivity.java
public class SecondActivity extends AppCompatActivity {
private EditText etInput;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
etInput = findViewById(R.id.et_input);
Button btnConfirm = findViewById(R.id.btn_confirm);
btnConfirm.setOnClickListener(v -> sendMessageBack());
}
private void sendMessageBack() {
String message = etInput.getText().toString().trim();
Intent resultIntent = new Intent();
// 即使为空,也把空字符串带回去
resultIntent.putExtra("EXTRA_MESSAGE", message);
// 设置结果为成功,并附上数据
setResult(Activity.RESULT_OK, resultIntent);
finish(); // 结束自己,返回主页面
}
// 处理返回键,视为取消
@Override
public void onBackPressed() {
setResult(Activity.RESULT_CANCELED);
finish();
}
}
恭喜你!看到这里,你已经掌握了Activity之间“带娃回家”的核心奥义。最后再唠叨几个容易掉进去的坑:
请求码别重复: 如果你要启动多个不同的Activity拿结果,记得给它们分配独一无二的
requestCode。判空是美德: 在
onActivityResult 里处理
data 之前,最好先判断一下它是不是
null,防止空指针异常。
finish() 是关键: 小弟一定要记得调用
setResult() 之后
finish(),不然他会一直赖在屏幕上,结果也送不回去。
虽然现在更现代的
Activity Result API 和
Jetpack Compose 有了新的方式,但
startActivityForResult/onActivityResult 这套机制是理解整个流程的基石,掌握了它,万变不离其宗。
希望这次“Activity漂流记”能让你在Android开发的路上,少掉几根头发,多几分从容!快去你的代码里试试吧,让Activity们愉快地“交流”起来!