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)