前言:
如果使用androidX支持库中的ComponentActivity,会推荐使用registerForActivityResult的方式。但是对于不支持androidX的项目,或者就是继承自Activity的页面来说,startActivityForResult仍然是唯一的选择。
如果想了解androidX中推荐的方式,可以参考文章:forResult的替代品registerForActivityResult介绍
而本文来讲解一下,正常流程中startActivityForResult的完整实现原理。
本文主要分为5个部分:
第一章,简单介绍下startActivityForResult的使用方式。
然后开始我们讲解原理,我们以简单的Test1Activity跳转Test2Activity为例讲解,主要分为3个部分:
第二章,Test1Activity启动Test2Activity的流程,对应流程图中右上的部分;
第三章,Test2Activity中调用setResult和finish后的流程,对应流程图中左上的部分;
第四章,Test1Activity切换到前台时forResult被调用的流程,对应流程图中下面的部分;
一.使用简介
startActivityForResult的使用方式是很简单的,我们从一个Test1Activity启动另外一个Test2Activity的时候,在调用的时候,使用startActivityForResult替代startActivity方法即可。并且,在Test1Activity中重写onActivityResult方法。相关代码如下:
public class Test1Activity{
public void onClick(){
Intent intent = new Intent(this, Test2Activity.class);
startActivityForResult(intent, 100)
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data)
Log.e("Test1Activity", "onActivityResult,requestCode:${requestCode},resultCode:${resultCode}")
}
}
Test2Activity中,在finish方调用之前,只要调用setResult,就可以设置返回值。这样等到Test1Activity再次展示到前台的时候,Test1Activity中的onActivityResult方法就会收到来自Test2Activity中传递的数据。
public class Test2Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
setResult(200,new Intent())
}
}
二.启动流程
启动时,我们使用startActivityForResult的方式启动,然后调用到Instrumentation中的execStartActivity方法,最终通过binder的方法startActivity通知到系统侧。
相关代码如下:
public class Activity{
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {
...
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);
...
}
}
public class Instrumentation {
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {
...
int result = ActivityTaskManager.getService().startActivity(whoThread,who.getOpPackageName(), who.getAttributionTag(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()), token,target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
...
}
}
其实这里的调用流程和正常的启动流程是一样的,唯一的区别就是startActivity的传参不一样,正常启动的话,token=null,requestCode=-1。
系统侧收到通知后,构建启动事务类ActivityStarter,然后把resultTo/resultWho/requestCode添加到ActivityStarter中。
public class ActivityTaskManagerService {
public final int startActivity(IApplicationThread caller, ...) {
startActivityAsUser(...)
}
public final int startActivityAsUser(IApplicationThread caller, ...) {
...
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.execute();
}
}
class ActivityStarter {
int execute() {
...
res = executeRequest(mRequest);
...
}
private int executeRequest(Request request) {
...
final ActivityRecord r = new ActivityRecord.Builder(mService)
.setCaller(callerApp)
.setResultTo(resultRecord)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.build();
...
}
}
最终,在executeRequest方法中,把resultRecord/resultWho/requestCode绑定到ActivityRecord,至此,Test2Activity中的resultTo指向了Test1Activity。
三.设置返回值
接下来,我们一起看一下,Test2Activity中如何把相关的返回值,设置到系统Test1Activity对应的ActivityRecord上。
Test2Activity中,通过setResult方法设置返回值,最终都会存到Activity的成员变量mResultCode和mResultData中,相关代码如下:
public final void setResult(int resultCode, Intent data) {
synchronized (this) {
mResultCode = resultCode;
mResultData = data;
}
}
当Test2Activity中调用finish方法时,会把mResultCode和mResultData通过binder方法,通过finishActivity方法通知到系统侧。
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);
if (resultData != null) {
resultData.prepareToLeaveProcess(this);
}
if (ActivityClient.getInstance().finishActivity(mToken, resultCode, resultData, finishTask)) {
mFinished = true;
}
} else {
mParent.finishFromChild(this);
}
getAutofillClientController().onActivityFinish(mIntent);
}
系统响应的方法是ActivityClientController中的finishActivity方法,系统最终会把resultCode和resultData封装成到ResultInfo对象,记录到其成员变量resultTo的results上。而这里的resultTo就是第一章中,注册的Test1Activity所对应的ActivityRecord。
class ActivityClientController {
public boolean finishActivity(IBinder token, int resultCode, Intent resultData,
int finishTask) {
...
r.finishIfPossible(resultCode, resultData, resultGrants,"app-request", true /* oomAdj */);
}
}
class ActivityRecord {
ArrayList<ResultInfo> results;
int finishIfPossible(int resultCode, Intent resultData,NeededUriGrants resultGrants, String reason, boolean oomAdj) {
...
finishActivityResults(resultCode, resultData, resultGrants);
...
}
private void finishActivityResults(int resultCode, Intent resultData,NeededUriGrants resultGrants) {
if (resultTo != null) {
resultTo.addResultLocked(this, resultWho, requestCode, resultCode, resultData);
}else{
...
}
}
void addResultLocked(ActivityRecord from, String resultWho,int requestCode, int resultCode, Intent resultData) {
ActivityResult r = new ActivityResult(from, resultWho,
requestCode, resultCode, resultData);
if (results == null) {
results = new ArrayList<ResultInfo>();
}
results.add(r);
}
}
四.回调流程
然后等到Activity切换到前台的时候,最终都会调用到resumeTopActivity方法。这时候会判断其results是否为空,如果不为空,则说明设置过回调的内容。
则构建事务的时候,添加ActivityResultItem类型非生命周期事务,和生命周期ResumeActivityItem事务,最后通知到应用一侧。
final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,boolean deferPause) {
ArrayList<ResultInfo> a = next.results;
if (a != null) {
final int size = a.size();
if (!next.finishing && size > 0) {
if (DEBUG_RESULTS) {
Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a);
}
transaction.addCallback(ActivityResultItem.obtain(a));
}
}
...
mAtmService.getLifecycleManager().scheduleTransaction(transaction);
}
应用侧事务接收到后,分别处理非生命周期事务ResumeActivityItem和生命周期事务ActivityResultItem。
public class TransactionExecutor {
...
public void execute(ClientTransaction transaction) {
//处理非生命周期事务
executeCallbacks(transaction);
//处理生命周期事务
executeLifecycleState(transaction);
}
}
public class ActivityResultItem{
public void execute(ClientTransactionHandler client, ActivityClientRecord r,PendingTransactionActions pendingActions) {
client.handleSendResult(r, mResultInfoList, "ACTIVITY_RESULT");
}
}
public class ActivityThread extends ClientTransactionHandler{
public void handleSendResult(ActivityClientRecord r, List<ResultInfo> results, String reason) {
...
deliverResults(r, results, reason);
...
}
private void deliverResults(ActivityClientRecord r, List<ResultInfo> results, String reason) {
final int N = results.size();
for (int i=0; i<N; i++) {
ResultInfo ri = results.get(i);
r.activity.dispatchActivityResult(ri.mResultWho, ri.mRequestCode, ri.mResultCode, ri.mData, reason);
}
}
}
public class Activity {
void dispatchActivityResult(String who, int requestCode, int resultCode, Intent data, String reason) {
onActivityResult(requestCode, resultCode, data);
}
}
在执行ActivityResultItem的事务时,会执行其execute方法,最终会通知到ActivityThread的handleSendResult方法去处理回调通知事件,然后转交给deliverResults处理。而在这个方法中,会遍历所有的ResultInfo对象,然后把最终的resultCode和data传递给所对应的Activity,从而至此,Test1Activity的onActivityResult方法就会收到回调通知。
五.扩展性问题
问题1.T1跳转T2时,如果T2不是通过finish的方法结束,而是通过其它的方式被desotry,会怎样?举个例子,T1设置为singleTask,T1通过forResult的方式跳转T2,T2中再跳转T1,这时,系统会remove掉最上层的T2。此时,T1中的onActivityForResult还会收到回调通知吗?