The resources

AMS source code analysis (a)Activity lifecycle management

AMS source code analysis (two)onActivityResult execution process

onActivityResult

The onActivityResult mechanism belongs to the basic knowledge of Android. I think every Android programmer has used it. There is no more explanation here, but let’s see how to use it

AActivity jumps to BAcitivty and returns data from 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();
    }
Copy the code

When the BActivity finishes, the resultCode and requestCode are sent back through the onActivityResult of the AActivity

Intent.FLAG_ACTIVITY_FORWARD_RESULT

This is another representation of onActivityResult, and we often encounter scenario 1 in our daily development. I’m going to jump from Activity A to Activity B to Activity C 2. I’m going to return data from Activity C to Activity A 3. The jump hierarchy may have many levels, such as A ->B -> C -> D -> E, and so on

You might say, “This is easy. You can implement onActivityResult for every Activity, and use startActivityForResult for every jump.” That’s fine, but the code is a little redundant. In fact, Android has already figured out how to handle this scenario for us

Intent.FLAG_ACTIVITY_FORWARD_RESULT calls the onActivityResult of the first Activity directly from the last Activity

Example:

Take AActivity to BActivity to CActivity as an example:

AActivity starts the BActivity as startActivityForResult
    public static void start(Activity activity, int requestCode) {
        Intent intent = new Intent(activity, BActivity.class);
        activity.startActivityForResult(intent, requestCode);
    }
Copy the code
FLAG_ACTIVITY_FORWARD_RESULT: Intent.flag_activity_forward_result: 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);
    }
Copy the code

When CActivity and BActivity return, AActivity receives a message from CActivity

The source code parsing

ActivityResult Writes data

Article when we finish process of parsing the Activity is actually a little contact with the execution of some onActivity process, in the process of the Activity of the finish, will call to ActivityStack# finishActivityResultsLocked method

private void finishActivityResultsLocked(ActivityRecord r, int resultCode, ActivityRecord = 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 put ActivityResult in resultTo save resultto. addResultLocked(r, R.esultwho, R.equestcode, 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; }Copy the code

Input parameter meaning:

  • R: The Activity that will finish
  • ResultCode: The resultCode to be passed
  • ResultData: The Intent to deliver

This method wraps the Result information into a ResultIfo object and stores it in the list

ActivityResult data delivery

In the article, when we finish the analysis of the Activity process mentioned ActivityStack# resumeTopActivityInnerLocked method, Another function of this method is to pass an ActivityResult to an Activity, a resultTo

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;
    }
Copy the code

. By calling the next app. Thread. ScheduleSendResult will ResultInfo (next appToken, a) sent to the app in the process of the corresponding Activity, and the callback onActivityResult method

Intent. FLAG_ACTIVITY_FORWARD_RESULT implementation

FLAG_ACTIVITY_FORWARD_RESULT: Intent.flag_activity_forward_result: intent.flag_activity_forward_result: 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 get start source 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 ! If (requestCode >= 0) {// Add intent.flag_activity_forward_result = intent.flag_activity_forward_result ActivityOptions.abort(options); return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT; } // Assign the resultTo of the source Activity to the target 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); }Copy the code

FLAG_ACTIVITY_FORWARD_RESULT specifies whether the Intent has an intent. FLAG_ACTIVITY_FORWARD_RESULT tag, and if so, assigns the resultTo of the source Activity to the target Activity

If there are multiple intermediate activities, such as starting ABCDE five activities in this way, and BCD are all intermediate activities, then the resultTo delivery process is as follows: Intent.flag_activity_forward_result = intent.flag_activity_forward_result = intent.flag_activity_forward_result Add Intent. FLAG_ACTIVITY_FORWARD_RESULT, D get C ResultTo namely A 4 D E, add Intent. FLAG_ACTIVITY_FORWARD_RESULT, E get ResultTo namely A 5 D. Returning from E step by step, when returns, E will ResultInfo assigned to A, when the return to A trigger next. App. Thread. ScheduleSendResult (next appToken, A)