【问题标题】:Handling configuration change for async methods处理异步方法的配置更改
【发布时间】:2014-08-05 06:52:32
【问题描述】:

我有一个包含异步方法的活动。这种异步方法运行时间很长。在 async 方法返回后,需要更新 UI,并且一些控件会引用该活动。 目前,如果您在异步任务运行时没有更改配置(如屏幕旋转),则一切正常。但是,如果在运行时发生配置更改,则会抛出异常 Activity isdestroy 并且 UI 不会更新。从我所做的阅读来看,这似乎是因为异步方法捕获了上下文,然后尝试更新旧的上下文,这在配置更改后当然会被销毁。

我的问题是:解决这个问题的最佳方法是什么,或者在最坏的情况下解决这个问题?

【问题讨论】:

    标签: xamarin xamarin.android async-await c#-5.0


    【解决方案1】:

    我个人认为你只有三个选择

    • 您可以永久或临时禁用轮播,但这是一种不好的做法

    要永久禁用它设置 ConfigurationChanges

    [Activity(Label = "...", ConfigurationChanges = Android.Content.PM.ConfigChanges.KeyboardHidden | Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)]   
    

    要在任务工作时暂时禁用它,您应该禁用旋转处理,

    禁用

    this.RequestedOrientation = Android.Content.PM.ScreenOrientation.Nosensor;
    

    启用

    this.RequestedOrientation = Android.Content.PM.ScreenOrientation.Sensor;
    
    • 如果您使用片段,您可以使用RetainInstance = true 防止片段破坏。这可能有效,但我从未测试过。

    • 您可以使用CancelationToken 取消任务并在OnRestoreInstanceState() 中重新启动它 这是如何取消任务的示例

      { CancellationTokenSource cts; ... // If a download process is already underway, cancel it. if (cts != null) { cts.Cancel(); }
      // Now set cts to cancel the current process if the button is chosen again. CancellationTokenSource newCTS = new CancellationTokenSource(); cts = newCTS;
      try { //Send cts.Token to carry the message if there is a cancellation request. await AccessTheWebAsync(cts.Token); } // Catch cancellations separately. catch (OperationCanceledException) { ResultsTextBox.Text += "\r\nDownloads canceled.\r\n"; } catch (Exception) { ResultsTextBox.Text += "\r\nDownloads failed.\r\n"; } // When the process is complete, signal that another process can proceed. if (cts == newCTS) cts = null; }

    在任务中

    async Task AccessTheWebAsync(CancellationToken ct)
    {
        ...
        // Retrieve the website contents from the HttpResponseMessage.
        byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
    
        // Check for cancellations before displaying information about the 
        // latest site. 
        ct.ThrowIfCancellationRequested();
        ...
    }
    

    【讨论】:

    • 感谢您的建议。同意禁用轮换是一个糟糕的主意,所以我不会这样做。似乎具有保留状态的片段是最干净的解决方案。我没有考虑取消任务,但这也可以工作,但这意味着可能需要重新启动任务。鉴于我们是 C#,抛出一些事件也可以工作,但这似乎很混乱。将其标记为答案,因为它提供了最多的建议并提供了示例。
    【解决方案2】:

    您可以做很多事情,但请不要禁用手机转动屏幕的功能——那只会忽略您的用户。

    在高层次上,您必须做两件事:

    1. 确保异步任务继续运行,并且在 Activity 终止时不会重新启动。

    您可以通过将任务移动到应用程序类或(更清洁)到 setRetainInstance 设置为 true 的无头片段中来解决这个问题。

    1. 在 Activity 的 onDestroy 方法中,将其从异步任务中移除,在 onCreate 任务中将 Activity 赋予异步任务(如果存在)。

    这是阻止异步任务调用旧上下文的原因,可以通过异步任务上的简单 java setter 来完成。如果活动当前未连接,请不要忘记将结果缓存在任务中。

    【讨论】:

    • 感谢您的建议。我同意禁用轮换非常糟糕,我不会这样做。异步任务永远不会因轮换而死,所以这不是问题。似乎具有保留状态的片段是最干净的解决方案。
    【解决方案3】:

    最后,我最终将异步任务封装在另一个类中,该类包含对当前活动的引用,该活动实现了接口,该接口定义了一个处理异步响应和更新 UI 的方法。

    Activity 持有封装异步任务的静态变量,如果它在配置更改期间运行,则封装异步任务对 Activity 的引用将更新为新 Activity。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-02
      • 1970-01-01
      • 1970-01-01
      • 2019-03-19
      • 1970-01-01
      • 2014-01-30
      • 1970-01-01
      相关资源
      最近更新 更多