async Task.Run lambda 表达式在 Android 上使 Unity AR 应用程序崩溃,但在 iOS 上运行良好

Posted

技术标签:

【中文标题】async Task.Run lambda 表达式在 Android 上使 Unity AR 应用程序崩溃,但在 iOS 上运行良好【英文标题】:async Task.Run lambda expression crashes Unity AR app on android but works fine on iOS 【发布时间】:2021-09-23 23:34:16 【问题描述】:

我正在使用 Unity 2020.3.4 和 ARCore 4.0.12 以及 Azure Spatial Anchors 2.8.1 创建一个应用程序。它是适用于 androidios 的跨平台应用程序。首先,我创建了一个 iOS 版本,在其中创建了一个 Task.Run(async() => ); void 函数中的 lambda 表达式,以便能够调用 Azure 空间锚的异步函数。我是这样做的,因为这个函数是在按下 Unity 按钮时调用的,它不需要异步任务,但它确实需要 void。这在 iOS 设备上运行良好,但在我在 Android 设备上测试后,此代码使应用程序崩溃。

//Called on Unity UI button press, works fine on IOS, but crashes the app on Android
public void BROKENStartLookingForAnchor()

    Task.Run(async () =>
    
        if (!hasStartedOnce)
        
            await StorageManager.instance.InitializeStorage();
            anchorId = await StorageManager.instance.DownloadBlob(blobName);
        

        spatialAnchorManager.SessionStarted += OnSessionStarted;
        spatialAnchorManager.AnchorLocated += CloudManager_AnchorLocated;

        anchorLocateCriteria = new AnchorLocateCriteria();

        if (spatialAnchorManager.Session == null)
        
            await spatialAnchorManager.CreateSessionAsync();
            SetAnchorLocateCriteria();
        

        await spatialAnchorManager.StartSessionAsync();
    );

一开始很难找出问题所在(我使用 LogCat 进行调试),但是一旦我将代码更改为以下代码,它在 Android 上也能正常工作。

//Called on Unity UI button press, because cannot call async Task from Unity button press
public async void StartLookingForAnchor()

    await StartLookingForAnchorAsync();


private async Task StartLookingForAnchorAsync()

    if (!hasStartedOnce)
    
        await StorageManager.instance.InitializeStorage();
        anchorId = await StorageManager.instance.DownloadBlob(blobName);
    

    spatialAnchorManager.SessionStarted += OnSessionStarted;
    spatialAnchorManager.AnchorLocated += CloudManager_AnchorLocated;

    anchorLocateCriteria = new AnchorLocateCriteria();

    if (spatialAnchorManager.Session == null)
    
        await spatialAnchorManager.CreateSessionAsync();
        SetAnchorLocateCriteria();
    

    await spatialAnchorManager.StartSessionAsync();

但是,即使我解决了这个问题,我仍然不确定为什么第一个选项在 Android 上不起作用,以及为什么第二个可以,因为我对异步函数和多线程不是很熟悉。谁能给我解释一下?

【问题讨论】:

【参考方案1】:

查看这些问题

https://github.com/Azure/azure-spatial-anchors-samples/issues/230 https://github.com/Azure/azure-spatial-anchors-samples/issues/283

如果您遇到类似错误,请尝试 Vastja 提到的解决方法

【讨论】:

【参考方案2】:

Task.Run(async () => ... ); 返回一个Task,在您的第一个版本中没有等待,其中BROKENStartLookingForAnchorAsync() 的返回类型仅为void

在您的第二个版本中,等待由async Task StartLookingForAnchorAsync() 返回的Task(这可以通过具有async void 返回类型的StartLookingForAnchor() 实现)。

我怀疑如果您将第一个版本返回 async void 并将代码设置为 await Task.Run(async () => ... );,或者只是删除了完全包裹其余代码的 Task.Run(),那么您的第一个版本也可以工作。

不鼓励使用 C# async documentation、async void 返回类型,但事件处理程序除外,这听起来像是按下 Unity 按钮的用例。

Unity QuickStart tutorials in the Azure Spatial Anchors documentation 可能是用于 Unity + ASA 的模式的良好起点。

【讨论】:

以上是关于async Task.Run lambda 表达式在 Android 上使 Unity AR 应用程序崩溃,但在 iOS 上运行良好的主要内容,如果未能解决你的问题,请参考以下文章

了解 async / await 和 Task.Run()

async await task.run xamarin 表单

C# Task.Run() 与 C++ std::async()

正确使用 Task.Run 和 async-await 时

正确使用 Task.Run 和 async-await 时

Task.Run(()=> DoWorkAsync()) 和 new Thread(async()=> DoWorkAsync()); 的区别