如何获取startActivityForResult启动的Activity实例并接收回调结果?
问题分析与解决方案
为什么直接new Activity实例会崩溃
Activity是Android系统管控的核心组件,绝对不能通过直接调用构造函数new来创建实例。Android系统需要为Activity初始化上下文、窗口、生命周期管理等核心依赖,这些步骤只有在通过Intent启动Activity时才会由系统自动完成。直接调用构造函数生成的Activity实例缺少这些必要初始化,必然触发崩溃。
正确获取Activity实例并启动带结果的Activity的步骤
1. 在Java层留存已初始化的Activity实例
首先要拿到一个被系统正确初始化的Activity实例,最简单的方式是在目标Activity中保留静态实例,并提供JNI可调用的入口:
package myPackage; import android.content.Intent; import android.os.Bundle; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.appcompat.app.AppCompatActivity; public class MyActivity extends AppCompatActivity implements PaymentControllerListener { private static MyActivity sInstance; // Android 11+推荐用ActivityResultLauncher替代已废弃的startActivityForResult private ActivityResultLauncher<Intent> mResultLauncher; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); sInstance = this; // 注册Activity结果回调 mResultLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == RESULT_OK) { Intent data = result.getData(); // 将结果传递给Native层 nativeOnActivityResult(result.getResultCode(), data); } } ); } // 给JNI提供获取当前Activity实例的静态方法 public static MyActivity getInstance() { return sInstance; } // 给JNI调用的启动目标Activity的方法 public void launchTargetActivity() { Intent intent = new Intent(this, TargetActivity.class); mResultLauncher.launch(intent); } // 接收结果并传递给Native层的Native方法 private native void nativeOnActivityResult(int resultCode, Intent data); @Override protected void onDestroy() { super.onDestroy(); // 清空静态引用,防止内存泄漏 sInstance = null; } // 实现PaymentControllerListener接口的方法... }
2. 在NDK层获取实例并启动目标Activity
通过JNI调用Java层的静态方法拿到已初始化的Activity实例,再调用启动方法:
#include <jni.h> #include <android/log.h> #define LOG_TAG "NativeActivityDemo" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) // 全局引用保存Activity实例,避免被GC回收 jobject gGlobalActivity = nullptr; extern "C" JNIEXPORT void JNICALL Java_myPackage_MyActivity_nativeOnActivityResult(JNIEnv* env, jobject thiz, int resultCode, jobject data) { // 处理返回结果 if (resultCode == -1) { // Android中RESULT_OK的常量值为-1 jclass intentClass = env->FindClass("android/content/Intent"); jmethodID getStringExtra = env->GetMethodID(intentClass, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;"); jstring resultKey = env->NewStringUTF("result_data"); jstring resultStr = (jstring)env->CallObjectMethod(data, getStringExtra, resultKey); const char* result = env->GetStringUTFChars(resultStr, nullptr); LOGI("Received activity result: %s", result); // 释放局部引用 env->ReleaseStringUTFChars(resultStr, result); env->DeleteLocalRef(resultKey); env->DeleteLocalRef(resultStr); env->DeleteLocalRef(intentClass); } } extern "C" JNIEXPORT void JNICALL Java_myPackage_MyNativeHelper_launchTargetActivityFromNative(JNIEnv* env, jobject thiz) { // 获取MyActivity类引用 jclass myActivityClass = env->FindClass("myPackage/MyActivity"); if (myActivityClass == nullptr) { LOGI("Failed to find MyActivity class"); return; } // 调用静态方法获取Activity实例 jmethodID getInstanceMethod = env->GetStaticMethodID(myActivityClass, "getInstance", "()LmyPackage/MyActivity;"); jobject activityObj = env->CallStaticObjectMethod(myActivityClass, getInstanceMethod); if (activityObj == nullptr) { LOGI("Failed to get MyActivity instance"); env->DeleteLocalRef(myActivityClass); return; } // 创建全局引用,避免实例被GC回收 if (gGlobalActivity == nullptr) { gGlobalActivity = env->NewGlobalRef(activityObj); } // 调用启动目标Activity的方法 jmethodID launchMethod = env->GetMethodID(myActivityClass, "launchTargetActivity", "()V"); env->CallVoidMethod(gGlobalActivity, launchMethod); // 释放局部引用 env->DeleteLocalRef(activityObj); env->DeleteLocalRef(myActivityClass); }
3. 关键注意事项
- 防止内存泄漏:在Activity的
onDestroy方法中清空静态实例引用,不需要全局引用时调用env->DeleteGlobalRef(gGlobalActivity)释放资源。 - 版本兼容:如果项目仍在使用Android 10及以下,可继续使用
startActivityForResult,但推荐迁移到ActivityResultContractsAPI(前者已被官方废弃)。 - 线程安全:如果在非UI线程调用JNI方法,需确保Activity实例处于活跃状态,避免调用已销毁的Activity方法引发崩溃。
内容的提问来源于stack exchange,提问作者Zaitsev Ilya
相关产品推荐
相关产品推荐

