You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 09:05:36