Android.OS.NetworkOnMainThreadException:在 async/await 块中

Yur*_*biy 3 c# android asynchronous xamarin.android xamarin

我正在尝试从指向图像的 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;
        }
Run Code Online (Sandbox Code Playgroud)

它恰好发生在这一行:

var stream = connection.InputStream;
Run Code Online (Sandbox Code Playgroud)

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

我已检查互联网许可。

这是 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);
                        });
Run Code Online (Sandbox Code Playgroud)

Sus*_*ver 7

ATask.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;
});
Run Code Online (Sandbox Code Playgroud)

  • 通过将方法中的所有内容包装在等待的“任务”中,我们现在立即处于不同的线程上,并且 Android 对您的网络调用感到满意。事实上,我们可能在一堆不同的线程上执行,因为每个等待的“Task”及其延续“可能”是不同的线程,但永远不会在原始调用线程上,因为它是主 UI 循环线程,而不是在系统创建的线程池中可用。这也是您必须执行“Device.BeginInvokeOnMainThread”的方式,以便您的 UI 更新将在正确的线程上执行。 (2认同)