AMS源码分析(二)onActivityResult执行过程

1,761 阅读3分钟

参考资料

AMS源码分析(一)Activity生命周期管理

AMS源码分析(二)onActivityResult执行过程

onActivityResult

onActivityResult机制的使用,属于Android基础知识,我想每一个Android程序员都用过,这里就不多做解释了,看一下使用方式

AActivity跳转BAcitivty并从BActivity返回数据

// AActivity
@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        activityName = "AActivity";
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_stack_test);
        jumpBtn = findViewById(R.id.jumpBtn);
        jumpBtn.setOnClickListener(v -> {
            BActivity.start(this, 1);
        });
        setActivityName();
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d("zyl", activityName + "      requestCode = " + requestCode + "       resultCode = " + resultCode);
        super.onActivityResult(requestCode, resultCode, data);
    }


// BActivity
public static void start(Activity activity, int requestCode) {
        activity.startActivityForResult(new Intent(activity, BActivity.class), requestCode);
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        activityName = "BActivity";
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_stack_test);
    }

    @Override
    public void finish() {
        setResult(102);
        super.finish();
    }

当BActivity finish时,会将resultCode和requestCode通过AActivity的onActivityResult回传回来

Intent.FLAG_ACTIVITY_FORWARD_RESULT

这是onActivityResult的另一种表现形式,在日常开发中我们经常会遇到如下场景 1.我要从Activity A 跳到B再跳到C 2.我要从Activity C 返回数据给Activity A 3.这种跳转层级有可能有很多层,比如 A ->B -> C -> D -> E等等

有同学看完肯定会说,这个简单啊,每个Activity都实现onActivityResult,每次跳转都使用startActivityForResult不就行了,这样当然可以,但是代码会稍显冗余。实际上,Android系统已经帮我们想好了这种场景的处理方式了

Intent.FLAG_ACTIVITY_FORWARD_RESULT的作用就是最后一个Activity直接调用第一个Activity的onActivityResult

示例:

以AActivity跳转BActivity跳转CActivity为例:

AActivity以startActivityForResult方式打开BActivity
    public static void start(Activity activity, int requestCode) {
        Intent intent = new Intent(activity, BActivity.class);
        activity.startActivityForResult(intent, requestCode);
    }
BActivity以普通方式打开CActivity,设置Intent 的Flag Intent.FLAG_ACTIVITY_FORWARD_RESULT
    public static void start(Context context) {
        Intent intent = new Intent(context, CActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
        context.startActivity(intent);
    }

CActivity和BActivity返回后,AActivity会接收到从CActivity传递过来的消息

源码解析

ActivityResult数据的写入

上篇文章我们在解析Activity的finish过程时其实稍微接触了一些onActivity的执行流程,在Activity的finish过程中,会调用到ActivityStack#finishActivityResultsLocked方法

private void finishActivityResultsLocked(ActivityRecord r, int resultCode, Intent resultData) {
        // zhangyulong 将结果传递给谁
        ActivityRecord resultTo = r.resultTo;
        if (resultTo != null) {
            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "Adding result to " + resultTo
                    + " who=" + r.resultWho + " req=" + r.requestCode
                    + " res=" + resultCode + " data=" + resultData);
            if (resultTo.userId != r.userId) {
                if (resultData != null) {
                    resultData.prepareToLeaveUser(r.userId);
                }
            }
            if (r.info.applicationInfo.uid > 0) {
                mService.grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
                        resultTo.packageName, resultData,
                        resultTo.getUriPermissionsLocked(), resultTo.userId);
            }
            // zhangyulong 将ActivityResult结果放在resultTo中保存
            resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
                                     resultData);
            r.resultTo = null;
        }
        else if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "No result destination from " + r);
        r.results = null;
        r.pendingResults = null;
        r.newIntents = null;
        r.icicle = null;
    }

入参含义:

  • r:即将finish的Activity
  • resultCode: 要传递的resultCode
  • resultData:要传递的Intent 这个方法将result信息封装成一个ResultIfo对象,并保存在列表中

ActivityResult数据的传递

在上篇文章中,我们在分析Activity的finish流程时提到过ActivityStack#resumeTopActivityInnerLocked方法,这个方法还有一个作用就是向上一个Activity,即resultTo传递ActivityResult

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        ...
        if (next.app != null && next.app.thread != null) {
            ...
            synchronized(mWindowManager.getWindowManagerLock()) {
                ...
                try {
                    // Deliver all pending results.
                    ArrayList<ResultInfo> a = next.results;
                    if (a != null) {
                        final int N = a.size();
                        if (!next.finishing && N > 0) {
                            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                                    "Delivering results to " + next + ": " + a);
                            next.app.thread.scheduleSendResult(next.appToken, a);
                        }
                    }

            
                    ...
                }
            }

            ...
        } else {
           ....
        }

        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        return true;
    }

通过调用next.app.thread.scheduleSendResult(next.appToken, a)将ResultInfo发送到App进程中对应的Activity中,并回调onActivityResult方法

Intent.FLAG_ACTIVITY_FORWARD_RESULT的实现

上篇文章我们分析过,Activity的启动流程会调用ActivityStarter#startActivity,这个方法有对Intent.FLAG_ACTIVITY_FORWARD_RESULT的处理,废话不多说,直接看源码:

private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, TaskRecord inTask) {
        ...

        ActivityRecord sourceRecord = null;
        ActivityRecord resultRecord = null;
        if (resultTo != null) {
            // zhangyulong 获取启动的源activity
            sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                    "Will send result to " + resultTo + " " + sourceRecord);
            if (sourceRecord != null) {
                if (requestCode >= 0 && !sourceRecord.finishing) {
                    resultRecord = sourceRecord;
                }
            }
        }
        if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
            // 添加Intent.FLAG_ACTIVITY_FORWARD_RESULT启动的Activity不能使用startActivityForResult启动
            if (requestCode >= 0) {
                ActivityOptions.abort(options);
                return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
            }
            // 将源Activity的resultTo赋值给目标Activity
            resultRecord = sourceRecord.resultTo;
            if (resultRecord != null && !resultRecord.isInStackLocked()) {
                resultRecord = null;
            }
            resultWho = sourceRecord.resultWho;
            requestCode = sourceRecord.requestCode;
            sourceRecord.resultTo = null;
            if (resultRecord != null) {
                resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
            }
            if (sourceRecord.launchedFromUid == callingUid) {
                callingPackage = sourceRecord.launchedFromPackage;
            }
        }
        ...
        return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                options, inTask, outActivity);
    }

代码比较简单,主要就是判断Intent中是否带有Intent.FLAG_ACTIVITY_FORWARD_RESULT标签,如果有,则将源Activity的resultTo赋值给目标Activity

如果有多个中间Activity,比如使用这种方式启动ABCDE五个Activity,其中,BCD都是中间Activity, 那么resultTo的传递过程如下: 1.A启动B,A作为resultTo传递给B 2.B启动C,添加Intent.FLAG_ACTIVITY_FORWARD_RESULT,C获取B的ResultTo即A 3.C启动D,添加Intent.FLAG_ACTIVITY_FORWARD_RESULT,D获取C的ResultTo即A 4.D启动E,添加Intent.FLAG_ACTIVITY_FORWARD_RESULT,E获取D的ResultTo即A 5.从E逐级返回,当E返回时,将ResultInfo赋值给A,当返回到A时,触发next.app.thread.scheduleSendResult(next.appToken, a)