Android ActivityResult 介绍
ActivityResult API 是 androidx.activity:activity 包引入的新 API,用来替代原有的 onActivityResult 获取上一个 Activity 返回的结果。
被废弃的 startActivityForResult 和 onActivityResult
startActivityForResult
从 ComponentActivity 的 startActivityForResult 方法 @Deprecated 注解可以看出这个方法已经被废弃,建议使用 registerForActivityResult 替代。
/**
* {@inheritDoc}
*
* @deprecated use
* {@link #registerForActivityResult(ActivityResultContract, ActivityResultCallback)}
* passing in a {@link StartActivityForResult} object for the {@link ActivityResultContract}.
*/
@Override
@Deprecated
public void startActivityForResult(@SuppressLint("UnknownNullness") Intent intent,
int requestCode) {
super.startActivityForResult(intent, requestCode);
}
onActivityResult
从 ComponentActivity 的 onActivityResult 方法 @Deprecated 注解可以看出这个方法已经被废弃,建议使用 registerForActivityResult 替代。
/**
* {@inheritDoc}
*
* @deprecated use
* {@link #registerForActivityResult(ActivityResultContract, ActivityResultCallback)}
* with the appropriate {@link ActivityResultContract} and handling the result in the
* {@link ActivityResultCallback#onActivityResult(Object) callback}.
*/
@CallSuper
@Override
@Deprecated
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (!mActivityResultRegistry.dispatchResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
ActivityResult 用法
registerForActivityResult
registerForActivityResult 是 ComponentActivity 的 public 方法,它接收一个 ActivityResultContract 和一个 ActivityResultCallback。
ActivityResultContract
ActivityResultContract 表示本次 Activity 启动的类型。
如果启动一个需要返回结果的 Activity,可以使用 ActivityResultContracts.StartActivityForResult()。
如果启动一个权限 Activity,就可以使用 ActivityResultContracts.RequestPermission()。
如果需要使用照片预览,可以使用 ActivityResultContracts.TakePicturePreview()。
ActivityResultCallback
ActivityResultCallback 表示上一个 Activity 回传的 ActivityResult 结果。
用法
首先使用 registerForActivityResult 得到 ActivityResultLauncher,在闭包中写上需要处理的ActivityResult。
private val activityResultLauncher: ActivityResultLauncher<Intent> =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult: ActivityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
// 收到 ActivityResult
}
}
如果要启动一个 Activity,使用 activityResultLauncher 的 launch 方法,替代原来的 startActivityForResult。
activityResultLauncher.launch(Intent(this, SecondActivity::class.java))
在需要返回结果的被启动 Activity 调用 setResult。
setResult(Activity.RESULT_OK, Intent().putExtra("key", "value"))
finish()
ActivityResult 好处
registerForActivityResult 的第一个参数 ActivityResultContracts 封装了很多常用的启动类型。不再需要调用者写不同 Activity 的启动代码。
使用 registerForActivityResult 之后也不需要再为 startActivityForResult 定义 requestCode。
ActivityResultContracts 有 14 个封装好的子类。
StartActivityForResult
常用的 Activity 启动,不带任何转换。
@NonNull
@Override
public Intent createIntent(@NonNull Context context, @NonNull Intent input) {
return input;
}
StartIntentSenderForResult
启动 IntentSender,调用了 Activity 的 startIntentSender 方法。
@NonNull
@Override
public Intent createIntent(@NonNull Context context, @NonNull IntentSenderRequest input) {
return new Intent(ACTION_INTENT_SENDER_REQUEST)
.putExtra(EXTRA_INTENT_SENDER_REQUEST, input);
}
RequestMultiplePermissions
请求多个权限
@NonNull
static Intent createIntent(@NonNull String[] input) {
return new Intent(ACTION_REQUEST_PERMISSIONS).putExtra(EXTRA_PERMISSIONS, input);
}
解析 Intent 调用了 ContextCompat.checkSelfPermission 方法。
@Override
public @Nullable SynchronousResult<Map<String, Boolean>> getSynchronousResult(
@NonNull Context context, @Nullable String[] input) {
if (input == null || input.length == 0) {
return new SynchronousResult<>(Collections.<String, Boolean>emptyMap());
}
Map<String, Boolean> grantState = new ArrayMap<>();
boolean allGranted = true;
for (String permission : input) {
boolean granted = ContextCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_GRANTED;
grantState.put(permission, granted);
if (!granted) allGranted = false;
}
if (allGranted) {
return new SynchronousResult<>(grantState);
}
return null;
}
RequestPermission
请求单个权限,间接调用了 RequestMultiplePermissions
@NonNull
@Override
public Intent createIntent(@NonNull Context context, @NonNull String input) {
return RequestMultiplePermissions.createIntent(new String[] { input });
}
TakePicturePreview
照片预览。构造 MediaStore.ACTION_IMAGE_CAPTURE 的 Intent。
new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
TakePicture
拍照并保存。传递 URI 作为保存路径。
public Intent createIntent(@NonNull Context context, @NonNull Uri input) {
return new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
.putExtra(MediaStore.EXTRA_OUTPUT, input);
}
TakeVideo
录像并保存。
public Intent createIntent(@NonNull Context context, @NonNull Uri input) {
return new Intent(MediaStore.ACTION_VIDEO_CAPTURE)
.putExtra(MediaStore.EXTRA_OUTPUT, input);
}
PickContact
选择通讯录
@NonNull
@Override
public Intent createIntent(@NonNull Context context, @Nullable Void input) {
return new Intent(Intent.ACTION_PICK).setType(ContactsContract.Contacts.CONTENT_TYPE);
}
GetContent
根据 Uri 从 ContentResolver 加载内容。
public Intent createIntent(@NonNull Context context, @NonNull String input) {
return new Intent(Intent.ACTION_GET_CONTENT)
.addCategory(Intent.CATEGORY_OPENABLE)
.setType(input);
}
GetMultipleContents
根据 Uri 从 ContentResolver 加载多个内容。
@CallSuper
@NonNull
@Override
public Intent createIntent(@NonNull Context context, @NonNull String input) {
return new Intent(Intent.ACTION_GET_CONTENT)
.addCategory(Intent.CATEGORY_OPENABLE)
.setType(input)
.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
}
OpenDocument
打开文档。
@CallSuper
@NonNull
@Override
public Intent createIntent(@NonNull Context context, @NonNull String[] input) {
return new Intent(Intent.ACTION_OPEN_DOCUMENT)
.putExtra(Intent.EXTRA_MIME_TYPES, input)
.setType("*/*");
}
OpenMultipleDocuments
打开多个文档。
@CallSuper
@NonNull
@Override
public Intent createIntent(@NonNull Context context, @NonNull String[] input) {
return new Intent(Intent.ACTION_OPEN_DOCUMENT)
.putExtra(Intent.EXTRA_MIME_TYPES, input)
.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
.setType("*/*");
}
OpenDocumentTree
打开目录。
@CallSuper
@NonNull
@Override
public Intent createIntent(@NonNull Context context, @Nullable Uri input) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& input != null) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, input);
}
return intent;
}
CreateDocument
创建文档
@CallSuper
@NonNull
@Override
public Intent createIntent(@NonNull Context context, @NonNull String input) {
return new Intent(Intent.ACTION_CREATE_DOCUMENT)
.setType("*/*")
.putExtra(Intent.EXTRA_TITLE, input);
}
ActivityResult 原理
ActivityResult 使用 ActivityResultLauncher 的 launch 方法代替了 startActivityForResult。
activityResultLauncher.launch(Intent(this, SecondActivity::class.java))
ActivityResultLauncher 是一个抽象类,它的 launch 方法如下:
ActivityResultLauncher
launch 方法调用了 2 个参数的 launch 抽象方法。
public void launch(@SuppressLint("UnknownNullness") I input) {
launch(input, null);
}
public abstract void launch(@SuppressLint("UnknownNullness") I input,
@Nullable ActivityOptionsCompat options);
registerForActivityResult
ComponentActivity 的 registerForActivityResult 方法调用了 registry 的 register 方法。mActivityResultRegistry 是 ComponentActivity 的私有类变量。
@NonNull
@Override
public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
@NonNull final ActivityResultContract<I, O> contract,
@NonNull final ActivityResultRegistry registry,
@NonNull final ActivityResultCallback<O> callback) {
return registry.register(
"activity_rq#" + mNextLocalRequestCode.getAndIncrement(), this, contract, callback);
}
@NonNull
@Override
public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
@NonNull ActivityResultContract<I, O> contract,
@NonNull ActivityResultCallback<O> callback) {
return registerForActivityResult(contract, mActivityResultRegistry, callback);
}
ActivityResultRegistry
ComponentActivity 的 mActivityResultRegistry 实现 ActivityResultRegistry 类的 onLaunch 抽象方法,表示 Intent 启动时需要做的事情。
ActivityResultRegistry.onLaunch
private final ActivityResultRegistry mActivityResultRegistry = new ActivityResultRegistry() {
@Override
public <I, O> void onLaunch(
final int requestCode,
@NonNull ActivityResultContract<I, O> contract,
I input,
@Nullable ActivityOptionsCompat options) {
ComponentActivity activity = ComponentActivity.this;
// Immediate result path
final ActivityResultContract.SynchronousResult<O> synchronousResult =
contract.getSynchronousResult(activity, input);
// 1. 如果有同步结果,发到主线程执行。
if (synchronousResult != null) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
dispatchResult(requestCode, synchronousResult.getValue());
}
});
return;
}
// 2. 从 ActivityResultContract 的 createIntent 方法获取 目标Intent。
// Start activity path
Intent intent = contract.createIntent(activity, input);
...
// 3. 处理权限请求。
if (ACTION_REQUEST_PERMISSIONS.equals(intent.getAction())) {
...
ActivityCompat.requestPermissions(activity, permissions, requestCode);
} else if (ACTION_INTENT_SENDER_REQUEST.equals(intent.getAction())) {
...
// 4. 处理 IntentSender。
...
ActivityCompat.startIntentSenderForResult(activity, request.getIntentSender(),
requestCode, request.getFillInIntent(), request.getFlagsMask(),
request.getFlagsValues(), 0, optionsBundle);
...
} else {
// 5. 其他情况调用 startActivityForResult
// startActivityForResult path
ActivityCompat.startActivityForResult(activity, intent, requestCode, optionsBundle);
}
}
};
ActivityResultRegistry.register
ActivityResultRegistry 的 register 方法返回了一个匿名内部类 ActivityResultLauncher,ActivityResultLauncher 的 launch 方法调用了 ActivityResultRegistry 的 onLaunch。
register 方法如下:
@NonNull
public final <I, O> ActivityResultLauncher<I> register(
@NonNull final String key,
@NonNull final LifecycleOwner lifecycleOwner,
@NonNull final ActivityResultContract<I, O> contract,
@NonNull final ActivityResultCallback<O> callback) {
...
LifecycleEventObserver observer = new LifecycleEventObserver() {
@Override
public void onStateChanged(
@NonNull LifecycleOwner lifecycleOwner,
@NonNull Lifecycle.Event event) {
if (Lifecycle.Event.ON_START.equals(event)) {
mKeyToCallback.put(key, new CallbackAndContract<>(callback, contract));
if (mParsedPendingResults.containsKey(key)) {
...
// 1. 预解析的同步的 ActivityResult
callback.onActivityResult(parsedPendingResult);
}
final ActivityResult pendingResult = mPendingResults.getParcelable(key);
if (pendingResult != null) {
...
// 2. 先调用 contract 解析,再返回 ActivityResult
callback.onActivityResult(contract.parseResult(
pendingResult.getResultCode(),
pendingResult.getData()));
}
} else if (Lifecycle.Event.ON_STOP.equals(event)) {
mKeyToCallback.remove(key);
} else if (Lifecycle.Event.ON_DESTROY.equals(event)) {
unregister(key);
}
}
};
...
return new ActivityResultLauncher<I>() {
// 3. launch 方法。
@Override
public void launch(I input, @Nullable ActivityOptionsCompat options) {
mLaunchedKeys.add(key);
// 4. 回调 ActivityResultRegistry 的 onLaunch 方法。
// 间接调用 ComponentActivity 的 startActivityForResult。
onLaunch(requestCode, contract, input, options);
}
@Override
public void unregister() {
ActivityResultRegistry.this.unregister(key);
}
@NonNull
@Override
public ActivityResultContract<I, ?> getContract() {
return contract;
}
};
}
总结
ActivityResult API 是 androidx.activity:activity 包引入的新 API,用来替代原有的 onActivityResult、requestCode 和 startActivityForResult。
ActivityResult 预置了一些常用的 Activity 启动类型,使用更为方便。
ActivityResultLauncher 的 launch 本质是在 ComponentActivity 的 ActivityResultRegistry 的 onLaunch 调用 startActivityForResult 启动 Activity。