C# 异步方法冻结用户界面

C# 异步方法冻结用户界面,c#,android,xamarin,xamarin.android,async-await,C#,Android,Xamarin,Xamarin.android,Async Await,预期结果: public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // [...] _fab = root.FindViewById<FloatingActionButton>(...); _fab.Click += ((sender, v) => TestAsync("fab"));

预期结果

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    // [...]

    _fab = root.FindViewById<FloatingActionButton>(...);
    _fab.Click += ((sender, v) =>  TestAsync("fab"));

    // [...]
}

private async void TestAsync(string origin)
{
    await LongTask(); 
}

private async Task LongTask()
{
    while (true) { } // Thread should hung here
}
UI线程调用
TestAsync
,工作线程执行
longstask

实际结果

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    // [...]

    _fab = root.FindViewById<FloatingActionButton>(...);
    _fab.Click += ((sender, v) =>  TestAsync("fab"));

    // [...]
}

private async void TestAsync(string origin)
{
    await LongTask(); 
}

private async Task LongTask()
{
    while (true) { } // Thread should hung here
}
Ui线程执行所有操作

测试

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    // [...]

    _fab = root.FindViewById<FloatingActionButton>(...);
    _fab.Click += ((sender, v) =>  TestAsync("fab"));

    // [...]
}

private async void TestAsync(string origin)
{
    await LongTask(); 
}

private async Task LongTask()
{
    while (true) { } // Thread should hung here
}
public override视图OnCreateView(布局、充气机、视图组容器、Bundle savedInstanceState)
{
// [...]
_fab=root.FindViewById(…);
_制造。点击+=((发送方,v)=>TestAsync(“制造”);
// [...]
}
专用异步void TestAsync(字符串源)
{
等待长任务();
}
专用异步任务
{
而(true){}//线程应该挂在这里
}
结果:Ui冻结

测试2: 为了确保UI执行所有操作,我做了一个网络操作(在Android的UI线程中是不允许的)

公共异步任务网络(字符串s)
{
URL=新URL(“http://www.randomtext.me/api/");
Java.IO.BufferedReader reader=new Java.IO.BufferedReader(new Java.IO.InputStreamReader(url.OpenStream());
整数计数=0;
字符串str;
而((str=reader.ReadLine())!=null){
计数+=长度;
}
reader.Close();
wait Task.Delay(3000);//确保此方法编译为异步方法,即使它不是必需的
返回计数;
}
结果:
NetworkOnMainThreadException

问题:

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    // [...]

    _fab = root.FindViewById<FloatingActionButton>(...);
    _fab.Click += ((sender, v) =>  TestAsync("fab"));

    // [...]
}

private async void TestAsync(string origin)
{
    // By not calling await you tell the code that you don't need this
    // calling method to await a return value.
    // using Task.Run explicitly requests another thread process this request
    Task.Run(LongTask); 
}

private async Task LongTask()
{
    while (true) { } // Thread should hung here
}
为什么工作线程中不执行
longstask
Network
方法?那么,
等待
/
异步
的是什么

谢谢

工作线程执行长任务

不,这不会自动发生。您等待GUI线程,因此将阻止它。此模式对于异步I/O是可以的,因为这将释放线程

但是,当您的案例受CPU限制时,异步/等待没有任何用处,请使用任务。运行:

private void TestAsync(string origin)
{
    Task.Run( LongTask); 
}
工作线程执行长任务

不,这不会自动发生。您等待GUI线程,因此将阻止它。此模式对于异步I/O是可以的,因为这将释放线程

但是,当您的案例受CPU限制时,异步/等待没有任何用处,请使用任务。运行:

private void TestAsync(string origin)
{
    Task.Run( LongTask); 
}
主要规则是:

  • 与ui相关的行为必须在主线程(ui线程)中
  • 网络/繁重任务必须在非主(ui)线程中执行
您试图从主(ui)线程执行网络任务,这导致出现此异常

尝试创建扩展AsyncTask类的TestAsync类。 然后重写doInBackground、onPostExecute方法

  • 在doInBackground方法中创建您的网络逻辑
  • 然后在onPostExecute方法中更新UI
这方面的参考:

主要规则是:

  • 与ui相关的行为必须在主线程(ui线程)中
  • 网络/繁重任务必须在非主(ui)线程中执行
您试图从主(ui)线程执行网络任务,这导致出现此异常

尝试创建扩展AsyncTask类的TestAsync类。 然后重写doInBackground、onPostExecute方法

  • 在doInBackground方法中创建您的网络逻辑
  • 然后在onPostExecute方法中更新UI

参考:任务一:异步/等待

private async void TestAsync(string origin)
{
    await LongTask(); 
}
说明:

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    // [...]

    _fab = root.FindViewById<FloatingActionButton>(...);
    _fab.Click += ((sender, v) =>  TestAsync("fab"));

    // [...]
}

private async void TestAsync(string origin)
{
    // By not calling await you tell the code that you don't need this
    // calling method to await a return value.
    // using Task.Run explicitly requests another thread process this request
    Task.Run(LongTask); 
}

private async Task LongTask()
{
    while (true) { } // Thread should hung here
}
调用按钮click事件委托时,将从主调度程序(UI线程)调用该委托。它告诉代理同步调用
TestAsync(“Fab”)
。当代理运行test async方法时,会告诉它运行任务
LongTask
,但您也会告诉它使用“wait”请求等待该任务的结果。因此,
TestAsync
方法在
longstask
完成之前无法完成;由于这是从主调度器请求的,UI的其余部分将挂起,直到完成为止

分辨率:

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    // [...]

    _fab = root.FindViewById<FloatingActionButton>(...);
    _fab.Click += ((sender, v) =>  TestAsync("fab"));

    // [...]
}

private async void TestAsync(string origin)
{
    // By not calling await you tell the code that you don't need this
    // calling method to await a return value.
    // using Task.Run explicitly requests another thread process this request
    Task.Run(LongTask); 
}

private async Task LongTask()
{
    while (true) { } // Thread should hung here
}
public override视图OnCreateView(布局、充气机、视图组容器、Bundle savedInstanceState)
{
// [...]
_fab=root.FindViewById(…);
_制造。点击+=((发送方,v)=>TestAsync(“制造”);
// [...]
}
专用异步void TestAsync(字符串源)
{
//通过不呼叫wait,您可以告诉代码您不需要这个
//调用方法以等待返回值。
//使用Task.Run显式请求另一个线程处理此请求
任务运行(长任务);
}
专用异步任务
{
而(true){}//线程应该挂在这里
}

任务二:网络

public async Task<int> Network(string s)
{
    URL url = new URL("http://www.randomtext.me/api/");
    Java.IO.BufferedReader reader = new Java.IO.BufferedReader(new Java.IO.InputStreamReader(url.OpenStream()));

    int count = 0;
    string str;
    while ((str = reader.ReadLine()) != null) {
        count += str.Length;
    }
    reader.Close();

    await Task.Delay(3000); // To make sure this method is compiled as async even though it isn't necessary

    return count;
}
公共异步任务网络(字符串s)
{
URL=新URL(“http://www.randomtext.me/api/");
Java.IO.BufferedReader reader=new Java.IO.BufferedReader(new Java.IO.InputStreamReader(url.OpenStream());
整数计数=0;
字符串str;
而((str=reader.ReadLine())!=null){
计数+=长度;
}
reader.Close();
wait Task.Delay(3000);//确保此方法编译为异步方法,即使它不是必需的
返回计数;
}
说明:

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    // [...]

    _fab = root.FindViewById<FloatingActionButton>(...);
    _fab.Click += ((sender, v) =>  TestAsync("fab"));

    // [...]
}

private async void TestAsync(string origin)
{
    // By not calling await you tell the code that you don't need this
    // calling method to await a return value.
    // using Task.Run explicitly requests another thread process this request
    Task.Run(LongTask); 
}

private async Task LongTask()
{
    while (true) { } // Thread should hung here
}
与之前一样,这在很大程度上取决于任务的启动方式,请参阅Microsoft文档中的以下引用:

async和await关键字不会导致添加额外的线程 创建。异步方法不需要多线程,因为异步 方法不在自己的线程上运行。该方法在当前服务器上运行 同步上下文,并且仅当 方法处于活动状态。您可以使用Task.Run将CPU绑定的工作移动到 后台线程,但后台线程对进程没有帮助 那只是等待结果出来


我希望这个答案能在回答你的问题时增加一些细节。

任务一:异步/等待

private async void TestAsync(string origin)
{
    await LongTask(); 
}
说明:

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    // [...]

    _fab = root.FindViewById<FloatingActionButton>(...);
    _fab.Click += ((sender, v) =>  TestAsync("fab"));

    // [...]
}

private async void TestAsync(string origin)
{
    // By not calling await you tell the code that you don't need this
    // calling method to await a return value.
    // using Task.Run explicitly requests another thread process this request
    Task.Run(LongTask); 
}

private async Task LongTask()
{
    while (true) { } // Thread should hung here
}
当按钮按下时