【问题标题】:Android.OS.NetworkOnMainThreadException: in async/await blockAndroid.OS.NetworkOnMainThreadException:在异步/等待块中
【发布时间】:2016-12-11 11:40:17
【问题描述】:

我正在尝试从指向图像的 URL 获取可绘制对象。但问题是,在 android 中你不应该在主线程上执行网络任务。正因为如此,我使用了 async/await 块,但错误仍然一直发生。代码如下:

page.Appearing += async(sender, ev3) =>
                    {
                        if ( GetToolbar == null ) return;

                        GetToolbar.Subtitle = viewModel?.SubTitle;

                        if ( viewModel == null ) return;

                        if ( viewModel.AvatarUrl.Contains("?") && !viewModel.AvatarUrl.Contains("gravatar") )
                            viewModel.AvatarUrl = viewModel.AvatarUrl
                                .Substring(0, viewModel.AvatarUrl.IndexOf("?", StringComparison.Ordinal));

                        //var stream = Context.ContentResolver.OpenInputStream(Android.Net.Uri.Parse(viewModel.AvatarUrl));

                        await SetLogo(viewModel);
 }

private async Task SetLogo(PublicRepositoryPageViewModel viewModel)
        {
            var url = new URL(viewModel.AvatarUrl);
            var connection = url.OpenConnection();
            var stream = connection.InputStream;
            var logo = await Drawable.CreateFromStreamAsync(stream, viewModel.Title + "_avatar");
            GetToolbar.Logo = logo;
        }

正好出现在这一行:

var stream = connection.InputStream;

如果我使用 OpenInputStream 而不是它,那么它会抛出 Java.IO.FileNotFoundException:没有内容提供者:https://avatars.githubusercontent.com/u/6516107

我已检查 Internet 权限。

它是 Xamarin.Forms Android 项目

回答:

await Task.Run(async() => {
                            var url = new URL(viewModel.AvatarUrl);
                            var connection = url.OpenConnection();
                            var stream = connection.InputStream;
                            var logo = await Drawable.CreateFromStreamAsync(stream, viewModel.Title + "_avatar");
                            Device.BeginInvokeOnMainThread(()=>GetToolbar.Logo = logo);
                        });

【问题讨论】:

    标签: c# android asynchronous xamarin xamarin.android


    【解决方案1】:

    Task.Run 将使您脱离主线程并进入默认线程池中的线程:

    await Task.Run(async() => {
      var url = new URL(viewModel.AvatarUrl);
      var connection = url.OpenConnection();
      var stream = connection.InputStream;
      var logo = await Drawable.CreateFromStreamAsync(stream, viewModel.Title + "_avatar");
      GetToolbar.Logo = logo;
    });
    

    【讨论】:

    • 你错过了 lambda 之前的 async 关键字。谢谢你。它做了一个伎俩。也许你有一些来源,可以解释它?
    • @YuraBabiy 谢谢,我修复了丢失的async
    • 仅使用async 标记方法不会导致方法体运行不同的线程。现在,一旦它遇到等待的任务,它就会将其推送到线程池(默认情况下),因此它不会阻塞调用线程(因此你有一个异步函数),现在“关闭”启动它的线程,在这种情况下,主要的 UI 消息传递/循环线程。等待的任务完成后,该方法的其余部分继续执行(这些称为continuations)并在线程池上执行(默认SynchronizationContext 是基于线程池的,但可以更改...)
    • 通过将您方法中的所有内容包装在等待的Task 中,我们现在立即进入另一个线程,Android 对您的网络调用感到满意。事实上,我们可能在一堆不同的线程上执行,因为每个等待 Task 及其延续“可能”是一个不同的线程,但永远不会在原始调用线程上,因为它是主 UI 循环线程,而不是在系统创建的线程池中可用。这也是您必须执行 Device.BeginInvokeOnMainThread 的方式,以便您的 UI 更新将在正确的线程上执行。
    猜你喜欢
    • 2021-10-22
    • 2013-10-12
    • 2015-01-09
    • 1970-01-01
    • 2019-03-04
    • 2014-09-06
    • 1970-01-01
    • 2017-11-14
    • 2023-03-12
    相关资源
    最近更新 更多