大厂Android面试秘籍:Activity 结果回调处理(八)

Android Activity 结果回调处理模块深度剖析

本人掘金号,欢迎点击关注:掘金号地址

本人公众号,欢迎点击关注:公众号地址

一、引言

在 Android 开发中,Activity 作为四大组件之一,承担着用户界面展示和交互的重要职责。而 Activity 之间的通信与交互更是开发过程中的常见需求,其中 Activity 结果回调处理模块尤为关键。当一个 Activity 启动另一个 Activity 并期望获取其返回结果时,就需要借助 Activity 结果回调机制。本博客将从源码级别深入分析 Android 的 Activity 结果回调处理模块,为开发者提供全面而深入的理解。

二、Activity 结果回调基础概念

2.1 基本使用场景

在 Android 应用中,经常会遇到一个 Activity 需要启动另一个 Activity 并获取其操作结果的情况。例如,在一个图片选择器应用中,主 Activity 启动图片选择 Activity,用户在图片选择 Activity 中选择了一张图片后,需要将该图片的信息返回给主 Activity。这就需要使用 Activity 结果回调机制来实现。

2.2 传统使用方式示例

以下是一个简单的传统 Activity 结果回调使用示例:

java

java 复制代码
// 主 Activity
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private static final int REQUEST_CODE = 1; // 请求码,用于区分不同的请求
    private TextView resultTextView; // 用于显示结果的 TextView

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        resultTextView = findViewById(R.id.resultTextView); // 初始化 TextView
        Button startActivityButton = findViewById(R.id.startActivityButton); // 初始化启动 Activity 的按钮

        // 为按钮设置点击事件监听器
        startActivityButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 创建启动目标 Activity 的 Intent
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                // 启动目标 Activity 并期望获取结果,传入请求码
                startActivityForResult(intent, REQUEST_CODE);
            }
        });
    }

    // 处理返回结果的方法
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // 检查请求码是否匹配
        if (requestCode == REQUEST_CODE) {
            // 检查结果码是否为 RESULT_OK
            if (resultCode == RESULT_OK) {
                // 从返回的 Intent 中获取数据
                String result = data.getStringExtra("result");
                // 将结果显示在 TextView 上
                resultTextView.setText("Result: " + result);
            }
        }
    }
}

// 目标 Activity
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;

public class SecondActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        Button returnResultButton = findViewById(R.id.returnResultButton); // 初始化返回结果的按钮

        // 为按钮设置点击事件监听器
        returnResultButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 创建用于返回数据的 Intent
                Intent resultIntent = new Intent();
                // 向 Intent 中添加数据
                resultIntent.putExtra("result", "This is the result");
                // 设置结果码为 RESULT_OK
                setResult(RESULT_OK, resultIntent);
                // 关闭当前 Activity
                finish();
            }
        });
    }
}

2.3 代码解释

  • MainActivity 中,通过 startActivityForResult 方法启动 SecondActivity 并传入请求码 REQUEST_CODE
  • SecondActivity 中,当用户点击 returnResultButton 时,创建一个包含结果数据的 Intent,并通过 setResult 方法设置结果码和返回的 Intent,最后调用 finish 方法关闭当前 Activity。
  • MainActivity 中的 onActivityResult 方法会在 SecondActivity 关闭后被调用,在该方法中检查请求码和结果码,并从返回的 Intent 中获取结果数据。

三、Activity 结果回调处理模块源码分析

3.1 startActivityForResult 方法源码分析

Activity 类中,startActivityForResult 方法的源码如下:

java

java 复制代码
/**
 * 启动一个新的 Activity 并期望获取其返回结果
 *
 * @param intent      用于启动 Activity 的 Intent
 * @param requestCode 请求码,用于区分不同的请求
 */
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
    if (mParent == null) {
        // 如果没有父 Activity,调用 Instrumentation 的 execStartActivity 方法
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, mOptions);
        if (ar != null) {
            // 如果有返回结果,调用 Activity 的 onActivityResult 方法
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
        // 检查启动 Activity 是否有过渡动画
        if (requestCode >= 0) {
            // 如果有过渡动画,设置 Activity 过渡动画
            mStartedActivity = true;
        }
    } else {
        // 如果有父 Activity,调用父 Activity 的 startActivityForResult 方法
        if (mOptions != null) {
            mParent.startActivityFromChild(this, intent, requestCode, mOptions);
        } else {
            mParent.startActivityFromChild(this, intent, requestCode);
        }
    }
}
3.1.1 代码解释
  • 首先检查当前 Activity 是否有父 Activity,如果没有父 Activity,则调用 mInstrumentation.execStartActivity 方法来启动目标 Activity。
  • mInstrumentation.execStartActivity 方法会返回一个 ActivityResult 对象,如果该对象不为空,则通过 mMainThread.sendActivityResult 方法将结果发送给当前 Activity 的 onActivityResult 方法进行处理。
  • 如果请求码大于等于 0,表示有过渡动画,设置 mStartedActivitytrue
  • 如果有父 Activity,则调用父 Activity 的 startActivityFromChild 方法来启动目标 Activity。

3.2 Instrumentation.execStartActivity 方法源码分析

Instrumentation 类中的 execStartActivity 方法源码如下:

java

java 复制代码
/**
 * 执行启动 Activity 的操作
 *
 * @param who         启动 Activity 的上下文
 * @param contextThread 应用程序的主线程
 * @param token       Activity 的令牌
 * @param target      目标 Activity
 * @param intent      用于启动 Activity 的 Intent
 * @param requestCode 请求码
 * @param options     启动 Activity 的选项
 * @return Activity 结果
 */
public ActivityResult execStartActivity(
    Context who, IBinder contextThread, IBinder token, Activity target,
    Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    Uri referrer = target != null ? target.onProvideReferrer() : null;
    if (referrer != null) {
        // 如果有引用者,将引用者添加到 Intent 中
        intent.putExtra(Intent.EXTRA_REFERRER, referrer);
    }
    if (mActivityMonitors != null) {
        // 如果有 Activity 监视器,检查是否匹配
        synchronized (mActivityMonitors) {
            final int N = mActivityMonitors.size();
            for (int i = 0; i < N; i++) {
                final ActivityMonitor am = mActivityMonitors.get(i);
                if (am.match(who, null, intent)) {
                    // 如果匹配,增加命中计数
                    am.mHits++;
                    if (am.isBlocking()) {
                        // 如果是阻塞监视器,返回模拟结果
                        return requestCode >= 0 ? am.getResult() : null;
                    }
                    break;
                }
            }
        }
    }
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        // 调用 ActivityManager 的 startActivityForResult 方法
        int result = ActivityManager.getService()
           .startActivity(whoThread, who.getBasePackageName(), intent,
                intent.resolveTypeIfNeeded(who.getContentResolver()),
                token, target != null ? target.mEmbeddedID : null,
                requestCode, 0, null, options);
        // 检查启动结果
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}
3.2.2 代码解释
  • 首先获取应用程序的主线程 whoThread,并检查是否有引用者,如果有则将引用者添加到 Intent 中。
  • 检查是否有 Activity 监视器,如果有则遍历监视器列表,检查是否匹配当前的 Intent,如果匹配则增加命中计数,若监视器为阻塞监视器,则返回模拟结果。
  • 调用 ActivityManager.getService().startActivity 方法来启动目标 Activity,并传入请求码等参数。
  • 调用 checkStartActivityResult 方法检查启动结果,如果出现异常则抛出 RuntimeException
  • 最后返回 null,因为真正的结果会在后续处理中返回。

3.3 ActivityManager.startActivity 方法源码分析

ActivityManager 类中的 startActivity 方法是一个系统服务方法,其源码涉及到系统底层的实现,以下是简化后的调用流程:

java

java 复制代码
// ActivityManagerService 中的 startActivity 方法(简化)
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions,
            UserHandle.getCallingUserId());
}

// ActivityManagerService 中的 startActivityAsUser 方法(简化)
@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
    enforceNotIsolatedCaller("startActivity");
    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
            false, ALLOW_FULL_ONLY, "startActivity", null);
    // 调用 ActivityStarter 的 startActivityMayWait 方法
    return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, bOptions, false, userId, null, null);
}
3.2.3 代码解释
  • startActivity 方法调用 startActivityAsUser 方法,并传入当前用户的 ID。
  • startActivityAsUser 方法会进行权限检查和用户 ID 处理,然后调用 ActivityStarterstartActivityMayWait 方法来启动目标 Activity。

3.4 ActivityStarter.startActivityMayWait 方法源码分析

ActivityStarter 类中的 startActivityMayWait 方法是启动 Activity 的核心方法,源码较长,以下是简化后的关键部分:

java

java 复制代码
// ActivityStarter 中的 startActivityMayWait 方法(简化)
int startActivityMayWait(IApplicationThread caller, int callingUid,
        String callingPackage, Intent intent, String resolvedType,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int startFlags,
        ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
        Bundle bOptions, boolean ignoreTargetSecurity, int userId,
        TaskRecord inTask, ActivityRecord[] outActivity) {
    // 解析 Intent
    ProcessRecord callerApp = null;
    if (caller != null) {
        callerApp = mService.getRecordForAppLocked(caller);
        if (callerApp != null) {
            callingUid = callerApp.info.uid;
            if (callingPackage == null) {
                callingPackage = callerApp.info.packageName;
            }
        }
    }
    // 创建 ActivityRecord 对象
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
            intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
            resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
            mSupervisor, checkedOptions, sourceRecord);
    // 调用 startActivityLocked 方法
    return startActivityLocked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
            true, options, inTask, outActivity);
}

// ActivityStarter 中的 startActivityLocked 方法(简化)
private int startActivityLocked(ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, Bundle options, TaskRecord inTask,
        ActivityRecord[] outActivity) {
    // 检查启动权限
    int err = ActivityManager.START_SUCCESS;
    if (r.resultTo != null) {
        // 如果有返回结果的目标,处理结果回调
        ActivityRecord resultTo = r.resultTo;
        if (resultTo.finishing) {
            // 如果结果目标 Activity 正在结束,不处理结果
            r.resultTo = null;
            err = ActivityManager.START_NOT_ACTIVITY;
        }
    }
    // 启动 Activity
    mLastStartActivityResult = err;
    mLastStartActivityRecord = r;
    if (err == ActivityManager.START_SUCCESS) {
        // 调用 resumeTopActivitiesLocked 方法启动 Activity
        mSupervisor.resumeTopActivitiesLocked(null, r, options);
    }
    return err;
}
3.2.4 代码解释
  • startActivityMayWait 方法会解析 Intent,创建 ActivityRecord 对象,该对象包含了 Activity 的相关信息,如请求码、结果目标等。
  • startActivityLocked 方法会检查启动权限,如果有返回结果的目标,会处理结果回调。如果结果目标 Activity 正在结束,则不处理结果。
  • 最后调用 mSupervisor.resumeTopActivitiesLocked 方法来启动目标 Activity。

3.5 Activity 结果返回处理源码分析

当目标 Activity 调用 setResult 方法并调用 finish 方法关闭时,会触发结果返回处理。以下是 Activity 类中 setResult 方法的源码:

java

java 复制代码
/**
 * 设置 Activity 的返回结果
 *
 * @param resultCode 结果码
 * @param data       用于返回的数据
 */
public final void setResult(int resultCode, Intent data) {
    synchronized (this) {
        // 设置结果码和返回数据
        mResultCode = resultCode;
        mResultData = data;
    }
}
3.2.5 代码解释
  • setResult 方法会将结果码和返回的数据存储在 Activity 的成员变量 mResultCodemResultData 中。

当目标 Activity 调用 finish 方法时,会触发以下处理:

java

java 复制代码
/**
 * 关闭当前 Activity
 */
public void finish() {
    finish(DONT_FINISH_TASK_WITH_ACTIVITY);
}

/**
 * 关闭当前 Activity 并指定是否关闭任务
 *
 * @param finishTask 是否关闭任务
 */
private void finish(int finishTask) {
    if (mParent == null) {
        int resultCode;
        Intent resultData;
        synchronized (this) {
            // 获取结果码和返回数据
            resultCode = mResultCode;
            resultData = mResultData;
        }
        if (false) Log.v(TAG, "Finishing self: token=" + mToken);
        try {
            if (resultData != null) {
                resultData.prepareToLeaveProcess(this);
            }
            // 调用 ActivityManager 的 finishActivity 方法
            if (ActivityManager.getService().finishActivity(mToken, resultCode, resultData, finishTask)) {
                mFinished = true;
            }
        } catch (RemoteException e) {
            // Empty
        }
    } else {
        // 如果有父 Activity,调用父 Activity 的 finishFromChild 方法
        mParent.finishFromChild(this);
    }
}
3.2.6 代码解释
  • finish 方法会获取之前设置的结果码和返回数据,并调用 ActivityManager.getService().finishActivity 方法将结果返回给启动该 Activity 的 Activity。
  • 如果有父 Activity,则调用父 Activity 的 finishFromChild 方法。

3.6 ActivityManager.finishActivity 方法源码分析

ActivityManager 类中的 finishActivity 方法源码如下:

java

java 复制代码
// ActivityManagerService 中的 finishActivity 方法(简化)
@Override
public final boolean finishActivity(IBinder token, int resultCode, Intent resultData,
        int finishTask) {
    // 查找对应的 ActivityRecord
    ActivityRecord r = ActivityRecord.isInStackLocked(token, mStackSupervisor);
    if (r == null) {
        return false;
    }
    // 处理结果回调
    if (r.resultTo != null) {
        ActivityRecord resultTo = r.resultTo;
        if (resultTo.finishing) {
            // 如果结果目标 Activity 正在结束,不处理结果
            r.resultTo = null;
        } else {
            // 发送结果给结果目标 Activity
            resultTo.deliverResultLocked(r, r.resultWho, r.requestCode, resultCode, resultData);
        }
    }
    // 关闭 Activity
    boolean res = mStackSupervisor.finishActivityLocked(r, resultCode, resultData, finishTask);
    return res;
}
3.2.7 代码解释
  • 首先根据传入的 token 查找对应的 ActivityRecord 对象。
  • 如果有结果目标 Activity 且该 Activity 没有正在结束,则调用 resultTo.deliverResultLocked 方法将结果发送给结果目标 Activity。
  • 最后调用 mStackSupervisor.finishActivityLocked 方法关闭当前 Activity。

3.7 ActivityRecord.deliverResultLocked 方法源码分析

ActivityRecord 类中的 deliverResultLocked 方法源码如下:

java

java 复制代码
// ActivityRecord 中的 deliverResultLocked 方法(简化)
void deliverResultLocked(ActivityRecord from, String resultWho, int requestCode,
        int resultCode, Intent resultData) {
    try {
        // 创建 ActivityResult 对象
        ActivityResult result = new ActivityResult(requestCode, resultCode, resultData);
        // 调用 ActivityClientRecord 的 sendResult 方法
        mApp.thread.scheduleSendResult(mToken, new ActivityResult[] { result });
    } catch (RemoteException e) {
        // Empty
    }
}
3.2.8 代码解释
  • 创建 ActivityResult 对象,包含请求码、结果码和返回数据。
  • 调用 mApp.thread.scheduleSendResult 方法将结果发送给结果目标 Activity 的主线程。

3.8 ActivityThread.scheduleSendResult 方法源码分析

ActivityThread 类中的 scheduleSendResult 方法源码如下:

java

java 复制代码
// ActivityThread 中的 scheduleSendResult 方法
@Override
public final void scheduleSendResult(IBinder token, ActivityResult[] results) {
    // 创建 Message 对象
    Message msg = Message.obtain();
    msg.what = H.SEND_RESULT;
    // 创建 ResultData 对象
    ResultData data = new ResultData();
    data.token = token;
    data.results = results;
    msg.obj = data;
    // 发送消息到主线程的 Handler
    mH.sendMessage(msg);
}
3.2.9 代码解释
  • 创建 Message 对象,设置消息类型为 H.SEND_RESULT
  • 创建 ResultData 对象,包含 ActivitytokenActivityResult 数组。
  • ResultData 对象设置为 Messageobj,并发送消息到主线程的 Handler

3.9 ActivityThread.H.handleMessage 方法中处理 SEND_RESULT 消息

ActivityThread 类的内部类 H 中,handleMessage 方法会处理 SEND_RESULT 消息,源码如下:

java

java 复制代码
// ActivityThread.H 中的 handleMessage 方法(处理 SEND_RESULT 消息)
case SEND_RESULT: {
    ResultData res = (ResultData) msg.obj;
    // 查找对应的 ActivityClientRecord
    ActivityClientRecord r = mActivities.get(res.token);
    if (r != null) {
        try {
            // 调用 Activity 的 deliverResults 方法
            r.activity.deliverResults(r, res.results);
        } catch (Exception e) {
            // Empty
        }
    }
    break;
}
3.2.10 代码解释
  • Message 中获取 ResultData 对象。
  • 根据 ResultData 中的 token 查找对应的 ActivityClientRecord 对象。
  • 如果找到对应的 ActivityClientRecord,则调用 ActivitydeliverResults 方法。

3.10 Activity.deliverResults 方法源码分析

Activity 类中的 deliverResults 方法源码如下:

java

java 复制代码
// Activity 中的 deliverResults 方法
void deliverResults(ActivityClientRecord r, ActivityResult[] results) {
    if (results != null) {
        for (int i = 0; i < results.length; i++) {
            // 调用 onActivityResult 方法处理结果
            onActivityResult(results[i].mRequestCode, results[i].mResultCode, results[i].mData);
        }
    }
}
3.2.11 代码解释
  • 遍历 ActivityResult 数组,调用 onActivityResult 方法处理每个结果。

四、新的 Activity 结果 API(AndroidX Activity Result API)

4.1 引入背景

传统的 startActivityForResultonActivityResult 方法在处理复杂场景时存在一些问题,例如代码逻辑分散、难以管理等。为了解决这些问题,AndroidX 引入了新的 Activity 结果 API。

4.2 基本使用示例

以下是一个使用新的 Activity 结果 API 的示例:

java

java 复制代码
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
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;

public class MainActivity extends AppCompatActivity {
    private TextView resultTextView; // 用于显示结果的 TextView
    private ActivityResultLauncher<Intent> activityResultLauncher; // Activity 结果启动器

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        resultTextView = findViewById(R.id.resultTextView); // 初始化 TextView
        Button startActivityButton = findViewById(R.id.startActivityButton); // 初始化启动 Activity 的按钮

        // 注册 Activity 结果启动器
        activityResultLauncher = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                new ActivityResultCallback<ActivityResult>() {
                    @Override
                    public void onActivityResult(ActivityResult result) {
                        // 处理返回结果
                        if (result.getResultCode() == RESULT_OK) {
                            Intent data = result.getData();
                            String resultText = data.getStringExtra("result");
                            resultTextView.setText("Result: " + resultText);
                        }
                    }
                });

        // 为按钮设置点击事件监听器
        startActivityButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 创建启动目标 Activity 的 Intent
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                // 启动目标 Activity
                activityResultLauncher.launch(intent);
            }
        });
    }
}

// 目标 Activity 保持不变
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;

public class SecondActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        Button returnResultButton = findViewById(R.id.returnResultButton); // 初始化返回结果的按钮

        // 为按钮设置点击事件监听器
        returnResultButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 创建用于返回数据的 Intent
                Intent resultIntent = new Intent();
                // 向 Intent 中添加数据
                resultIntent.putExtra("result", "This is the result");
                // 设置结果码为 RESULT_OK
                setResult(RESULT_OK, resultIntent);
                // 关闭当前 Activity
                finish();
            }
        });
    }
}

4.3 代码解释

  • 使用 registerForActivityResult 方法注册一个 ActivityResultLauncher,该方法接受一个 ActivityResultContract 和一个 ActivityResultCallback
  • ActivityResultContract 定义了启动 Activity 的方式和返回结果的类型,这里使用 ActivityResultContracts.StartActivityForResult 表示启动一个 Activity 并获取结果。
  • ActivityResultCallback 用于处理返回的结果,在 onActivityResult 方法中处理结果。
  • 当需要启动目标 Activity 时,调用 ActivityResultLauncherlaunch 方法,并传入启动 Activity 的 Intent

4.4 新 API 的源码分析

4.4.1 registerForActivityResult 方法源码分析

ComponentActivity 类中的 registerForActivityResult 方法源码如下:

java

java 复制代码
// ComponentActivity 中的 registerForActivityResult 方法
public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
        @NonNull ActivityResultContract<I, O> contract,
        @NonNull ActivityResultCallback<O> callback) {
    return getActivityResultRegistry().register(
            "activity_rq#" + nextLocalRequestCode(),
            this,
            contract,
            callback);
}
4.4.1.1 代码解释
  • 调用 getActivityResultRegistry().register 方法进行注册,传入一个唯一的请求码、当前 Activity、ActivityResultContractActivityResultCallback
4.4.2 ActivityResultRegistry.register 方法源码分析

ActivityResultRegistry 类中的 register 方法源码如下:

java

java 复制代码
// ActivityResultRegistry 中的 register 方法
public <I, O> ActivityResultLauncher<I> register(@NonNull final String key,
        @NonNull final LifecycleOwner lifecycleOwner,
        @NonNull final ActivityResultContract<I, O> contract,
        @NonNull final ActivityResultCallback<O> callback) {
    if (mParsedPendingResults.containsKey(key)) {
        // 如果有未处理的结果,立即处理
        final O parsedPendingResult = mParsedPendingResults.get(key);
        mParsedPendingResults.remove(key);
        callback.onActivityResult(parsedPendingResult);
    }
    // 创建 ActivityResultLauncher 对象
    final ActivityResultLauncher<I> launcher = new ActivityResultLauncher<I>() {
        @Override
        public void launch(I input, @Nullable ActivityOptionsCompat options) {
            // 启动 Activity
            mKeyToCallback.put(key, callback);
            mKeyToContract.put(key, contract);
            mLaunchedKeys.add(key);
            Intent intent = contract.createIntent(mContext, input);
            if (options != null) {
                ActivityCompat.startActivityForResult(
                        mContext,
                        intent,
                        mKeyToRc.get(key),
                        options.toBundle());
            } else {
                ActivityCompat.startActivityForResult(
                        mContext,
                        intent,
                        mKeyToRc.get(key),
                        null);
            }
        }

        @Override
        public void unregister() {
            // 取消注册
            mKeyToCallback.remove(key);
            mKeyToContract.remove(key);
            mLaunchedKeys.remove(key);
            mKeyToRc.remove(key);
        }

        @NonNull
        @Override
        public ActivityResultContract<I, O> getContract() {
            return contract;
        }
    };
    // 注册生命周期观察者
    lifecycleOwner.getLifecycle().addObserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                // 在 Activity 销毁时取消注册
                launcher.unregister();
            }
        }
    });
    return launcher;
}
4.4.2.1 代码解释
  • 检查是否有未处理的结果,如果有则立即处理。
  • 创建 ActivityResultLauncher 对象,该对象包含 launchunregistergetContract 方法。
  • launch 方法用于启动 Activity,将请求码、ActivityResultCallbackActivityResultContract 存储在相应的映射中,然后调用 ActivityCompat.startActivityForResult 方法启动 Activity。
  • unregister 方法用于取消注册,从映射中移除相应的信息。
  • 注册生命周期观察者,在 Activity 销毁时调用 unregister 方法取消注册。
4.4.3 ActivityResultRegistry.onActivityResult 方法源码分析

ActivityResultRegistry 类中的 onActivityResult 方法源码如下:

java

java 复制代码
// ActivityResultRegistry 中的 onActivityResult 方法
public boolean onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    String key = mRcToKey.get(requestCode);
    if (key == null) {
        return false;
    }
    mLaunchedKeys.remove(key);
    ActivityResultContract<?, ?> contract = mKeyToContract.get(key);
    ActivityResultCallback<?> callback = mKeyToCallback.get(key);
    if (contract != null && callback != null) {
        // 解析结果
        Object parsedResult = contract.parseResult(resultCode, data);
        // 调用回调方法处理结果
        callback.onActivityResult(parsedResult);
        return true;
    }
    return false;
}
4.4.3.1 代码解释
  • 根据请求码查找对应的 key,如果 key 不存在则返回 false
  • mLaunchedKeys 中移除该 key,表示该请求已经处理。
  • 获取对应的 ActivityResultContractActivityResultCallback
  • 调用 ActivityResultContractparseResult 方法解析结果。
  • 调用 ActivityResultCallbackonActivityResult 方法处理结果。

五、总结与展望

5.1 总结

通过对 Android 的 Activity 结果回调处理模块的源码分析,我们深入了解了传统的 startActivityForResultonActivityResult 方法以及新的 AndroidX Activity Result API 的实现原理。

传统方法的实现涉及到 ActivityInstrumentationActivityManager 等多个类,通过一系列的调用和消息传递来完成 Activity 的启动和结果返回。这种方式在处理复杂场景时存在代码逻辑分散、难以管理的问题。

新的 AndroidX Activity Result API 通过 ActivityResultLauncherActivityResultRegistry 来管理 Activity 的启动和结果处理,将代码逻辑集中在一起,提高了代码的可读性和可维护性。同时,新 API 还支持生命周期管理,在 Activity 销毁时自动取消注册,避免了内存泄漏。

5.2 展望

随着 Android 开发的不断发展,Activity 结果回调处理模块可能会进一步优化和完善。未来可能会有更简洁、更强大的 API 出现,以满足开发者在不同场景下的需求。

同时,对于 Activity 结果回调处理模块的性能优化也是一个重要的研究方向。例如,减少不必要的消息传递和对象创建,提高启动 Activity 和处理结果的效率。

另外,在跨进程和跨应用的 Activity 结果回调处理方面,也有很大的发展空间。可以研究如何更安全、更高效地实现跨进程和跨应用的结果传递,为开发者提供更好的开发体验。

总之,Activity 结果回调处理模块是 Android 开发中不可或缺的一部分,深入理解其原理和不断探索其发展方向,对于提高 Android 应用的开发质量和效率具有重要意义。

相关推荐
QING6181 小时前
详解:Kotlin 类的继承与方法重载
android·kotlin·app
QING6181 小时前
Kotlin 伴生对象(Companion Object)详解 —— 使用指南
android·kotlin·app
一一Null1 小时前
Android studio 动态布局
android·java·android studio
软件测试曦曦8 小时前
16:00开始面试,16:08就出来了,问的问题有点变态。。。
自动化测试·软件测试·功能测试·程序人生·面试·职场和发展
拉不动的猪8 小时前
设计模式之------策略模式
前端·javascript·面试
独行soc9 小时前
2025年常见渗透测试面试题-红队面试宝典下(题目+回答)
linux·运维·服务器·前端·面试·职场和发展·csrf
AD钙奶-lalala9 小时前
某车企面试备忘
android
uhakadotcom9 小时前
Google Earth Engine 机器学习入门:基础知识与实用示例详解
前端·javascript·面试
我爱拉臭臭9 小时前
kotlin音乐app之自定义点击缩放组件Shrink Layout
android·java·kotlin
uhakadotcom10 小时前
Amazon GameLift 入门指南:六大核心组件详解与实用示例
后端·面试·github