.NET MAUI Android:如何同步调用StartActivityForResult并等待返回结果
问题
需要在Android应用中启动外部App的Activity,并通过OnActivityResult获取返回结果。当前使用StartActivityForResult时,调用代码执行完毕后即退出,需等待外部Activity处理完成才会触发OnActivityResult。希望在ViewModel中通过async/await方式调用相关方法,实现业务代码线性编写,无需在OnActivityResult中使用回调。
现有代码逻辑:
public class MyViewModel { public async void OnCallExternalIntent() { // 内部调用StartActivityForResult,线程随即退出,OnActivityResult后续触发,逻辑正常但无法同步获取结果 androidService.CreateExternalIntent(); } }
期望的代码结构:
public class MyViewModel { public async void OnCallExternalIntent() { var otherActivityResult = await androidService.CreateExternalIntent(); // 直接处理返回结果,无需回调 } } public class MainActivity : MainApplication { public Task CreateNewActivity() { StartActivityForResult(planeteMonetiqueIntent, transaction.InteropMessageId); AutoResetEvent.WaitOne(); return Task.FromResult(_otherActivityResult); } } protected override void OnActivityResult(int requestCode, Result resultCode, Android.Content.Intent intent) { Bundle bundle = intent.Extras; _otherActivityResult = GetDataFromBundle(); AutoResetEvent.Set(); }
此前用类似逻辑同步USB设备获取Arduino处理结果时,await可正常工作,但尝试Instrumentation.StartActivitySync时报错,提示无法在主线程执行该代码,现寻求可行实现方案。
可行实现方案
你之前用AutoResetEvent.WaitOne()会阻塞主线程,这在Android中会引发ANR(应用无响应),正确的做法是用TaskCompletionSource<T>将OnActivityResult的回调逻辑转换为可await的Task,具体实现如下:
1. 封装ActivityResult异步处理逻辑
在MainActivity中维护一个字典,存储不同请求码对应的TaskCompletionSource,支持多并发的Activity启动请求:
public class MainActivity : MainApplication { private readonly Dictionary<int, TaskCompletionSource<ActivityResultData>> _pendingResults = new Dictionary<int, TaskCompletionSource<ActivityResultData>>(); private int _nextRequestCode = 1000; // 自定义起始请求码,避免与系统冲突 // 定义返回结果的实体类,按需调整字段 public class ActivityResultData { public Result ResultCode { get; set; } public Intent? Intent { get; set; } public YourDataType ParsedData { get; set; } } public async Task<ActivityResultData> CreateExternalIntent(Intent intent) { var requestCode = Interlocked.Increment(ref _nextRequestCode); var tcs = new TaskCompletionSource<ActivityResultData>(); lock (_pendingResults) { _pendingResults[requestCode] = tcs; } try { StartActivityForResult(intent, requestCode); return await tcs.Task; } catch (Exception ex) { tcs.TrySetException(ex); throw; } } protected override void OnActivityResult(int requestCode, Result resultCode, Intent? intent) { base.OnActivityResult(requestCode, resultCode, intent); lock (_pendingResults) { if (_pendingResults.TryGetValue(requestCode, out var tcs)) { _pendingResults.Remove(requestCode); // 解析返回数据 var resultData = new ActivityResultData { ResultCode = resultCode, Intent = intent, ParsedData = GetDataFromBundle(intent?.Extras) }; tcs.TrySetResult(resultData); } } } // 替换为你的Bundle解析逻辑 private YourDataType GetDataFromBundle(Bundle? bundle) { // 示例:return bundle?.GetString("target_key") ?? string.Empty; } }
2. ViewModel中的调用方式
在ViewModel中注入MainActivity实例(或通过接口抽象解耦),直接通过await获取结果:
public class MyViewModel { private readonly MainActivity _mainActivity; public MyViewModel(MainActivity mainActivity) { _mainActivity = mainActivity; } public async void OnCallExternalIntent() { try { var intent = new Intent(); // 设置外部App的组件信息,比如包名、目标Activity intent.SetComponent(new ComponentName("com.external.app", "com.external.app.TargetActivity")); var result = await _mainActivity.CreateExternalIntent(intent); // 线性处理返回结果 if (result.ResultCode == Result.Ok) { var parsedData = result.ParsedData; // 后续业务逻辑处理 } } catch (Exception ex) { // 处理启动失败或异常情况 } } }
关键说明
- 用
TaskCompletionSource替代AutoResetEvent,不会阻塞主线程,符合Android线程模型要求 - 字典维护多个待处理请求,支持同时启动多个外部Activity的场景
- 自定义请求码并通过
Interlocked.Increment保证线程安全,避免请求码冲突 - 数据解析逻辑封装在Activity中,ViewModel仅负责业务处理,符合MVVM职责分离原则
内容的提问来源于stack exchange,提问作者Julien Duprat
相关产品推荐
相关产品推荐

