avatar
Published on

Android startActivityForResult()废弃替代方案详解及实例

Android startActivityForResult()废弃替代方案详解及实例

Android startActivityForResult()废弃替代方案详解及实例

在Android开发中,当compileSdk版本为32或更高时,使用传统的startActivityForResult()方法会收到Android Studio的废弃警告。本文将详细介绍官方推荐的替代方案——Activity Result API的使用方法及实例。

为什么需要替代方案

传统的startActivityForResult()方法存在一些设计缺陷:

  • 回调处理与启动意图分离,导致代码分散
  • 需要重写onActivityResult()方法,处理所有页面的返回结果
  • 类型不安全,需要手动解析返回数据
  • 生命周期管理复杂,容易出现内存泄漏

Activity Result API介绍

Activity Result API是Android Jetpack的一部分,提供了更安全、更灵活的Activity结果处理机制,主要包括:

  • registerForActivityResult():注册Activity结果监听器
  • ActivityResultLauncher:启动Activity的启动器
  • ActivityResultCallback:处理返回结果的回调接口
  • ActivityResultContracts:预定义的启动契约集合

实现步骤

1. 添加依赖

确保在app模块的build.gradle文件中添加必要的依赖:

// 确保app的build.gradle中已经引入了必要的依赖
dependencies {
    implementation 'androidx.appcompat:appcompat:1.4.1'
    // Activity Result API已包含在appcompat库中
}

2. 源页面(A页面)实现

源页面负责启动目标页面并接收返回结果:

package com.example.test1;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import com.example.test1.ui.login.LoginActivity; // B页面例子

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";
    
    // 声明Activity结果启动器
    private ActivityResultLauncher<Intent> resultLauncher;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.my_button).setOnClickListener(this);

        // 注册Activity结果监听器
        resultLauncher = registerForActivityResult(
                // 使用预定义的StartActivityForResult契约
                new ActivityResultContracts.StartActivityForResult(), 
                // 实现结果回调处理
                new ActivityResultCallback<ActivityResult>() {
            @Override
            public void onActivityResult(ActivityResult result) {
                Log.i(TAG, "接收到Activity结果: " + result);
                
                // 安全检查
                if (result != null && result.getResultCode() == Activity.RESULT_OK) {
                    Intent data = result.getData();
                    if (data != null) {
                        // 获取返回的数据
                        String name = data.getStringExtra("my_name");
                        String sex = data.getStringExtra("my_sex");
                        
                        // 处理返回的数据
                        Log.i(TAG, "获取返回值 my_name: " + name);
                        Log.i(TAG, "获取返回值 my_sex: " + sex);
                        
                        // 在这里可以根据返回的数据执行相应的UI更新或业务逻辑
                    }
                }
            }
        });
    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.my_button) {
            // 创建跳转到B页面的意图
            Intent intent = new Intent(this, LoginActivity.class);
            
            // 可选:向前一个页面传递参数
            // intent.putExtra("key", "value");
            
            // 使用启动器启动Activity
            resultLauncher.launch(intent);
        }
    }
}

3. 目标页面(B页面)实现

目标页面负责处理业务逻辑并返回结果给源页面:

// B页面的后退逻辑示例
public void returnToPreviousPage(View view) {
    // 1. 创建返回意图
    Intent resultIntent = new Intent();
    
    // 2. 封装需要返回的数据
    resultIntent.putExtra("my_name", "zhangsan000");
    resultIntent.putExtra("my_sex", "男");
    
    // 也可以使用Bundle批量传递数据
    // Bundle resultBundle = new Bundle();
    // resultBundle.putString("my_name", "zhangsan000");
    // resultBundle.putString("my_sex", "男");
    // resultIntent.putExtras(resultBundle);
    
    // 3. 设置结果码和数据
    // RESULT_OK 表示操作成功
    setResult(Activity.RESULT_OK, resultIntent);
    
    // 4. 结束当前页面,返回上一页
    finish();
}

代码优化建议

  1. 使用类型安全的自定义Contract:对于频繁使用的页面跳转,可以定义自定义Contract简化代码:
// 自定义Contract示例
class UserInfoContract extends ActivityResultContract<Void, UserInfo> {
    @Override
    public Intent createIntent(Context context, Void input) {
        return new Intent(context, LoginActivity.class);
    }

    @Override
    public UserInfo parseResult(int resultCode, @Nullable Intent intent) {
        if (resultCode != Activity.RESULT_OK || intent == null) {
            return null;
        }
        String name = intent.getStringExtra("my_name");
        String sex = intent.getStringExtra("my_sex");
        return new UserInfo(name, sex);
    }
}

// 使用自定义Contract
resultLauncher = registerForActivityResult(
    new UserInfoContract(),
    userInfo -> {
        if (userInfo != null) {
            // 直接使用UserInfo对象
        }
    }
);
  1. 在Fragment中使用:在Fragment中使用与Activity类似,但需要注意生命周期:
// Fragment中注册时需要指定生命周期所有者
resultLauncher = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    result -> {
        // 处理结果
    }
);

总结

Activity Result API相比传统的startActivityForResult()方法,具有以下优势:

  • 代码组织更清晰:启动和回调处理封装在一起
  • 类型安全:可以通过自定义Contract实现类型安全的数据传递
  • 生命周期感知:自动管理生命周期,避免内存泄漏
  • 扩展性更好:支持各种预定义的启动契约,也支持自定义契约

通过采用Activity Result API,可以使Android应用的页面间通信更加安全和高效。