预期结果:
UI线程调用 TestAsync
,工作线程执行LongTask
。
实际结果:
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
}
结果:Ui冻结了。
测试2 : 为了确保UI正在执行所有操作,我改为进行了网络操作(在Android的UI线程中不允许)
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;
}
结果:NetworkOnMainThreadException
。
问题:
为什么在工作线程中没有执行LongTask
或Network
方法?什么是await
/ async
呢?
感谢。
答案 0 :(得分:3)
并且工作线程执行LongTask。
不,这本身不会发生。您等待GUI线程,因此您将阻止它。这种模式适用于异步I / O,因为这将释放线程。
但是当你的情况是CPU绑定时,async / await没有用,请使用Task.Run:
private void TestAsync(string origin)
{
Task.Run( LongTask);
}
答案 1 :(得分:0)
主要规则是:
您尝试从主(ui)线程执行网络任务,它导致您遇到此异常。
尝试创建扩展AsyncTask类的TestAsync类。 然后覆盖doInBackground,onPostExecute方法。
参考:http://programmerguru.com/android-tutorial/what-is-asynctask-in-android/
答案 2 :(得分:0)
任务一:async / await
private async void TestAsync(string origin)
{
await LongTask();
}
<强>解释强>
当按钮单击事件委托被调用时,它将从主调度程序(UI线程)调用。它告诉委托同步调用TestAsync("Fab")
。当委托运行测试异步方法时,会告诉它运行任务LongTask
,但您也要告诉它等待该任务的结果,使用&#39; await&#39;请求。因此,在TestAsync
完成之前,LongTask
方法无法完成;因为这是从主调度员请求的,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 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;
}
<强>解释强>
如前所述,这在很大程度上取决于任务的启动方式,请参阅Microsoft文档中的引用:
async和await关键字不会导致额外的线程 创建。异步方法不需要多线程,因为异步 方法不会在自己的线程上运行。该方法在当前运行 同步上下文并仅在线程上使用时间 方法是有效的。您可以使用Task.Run将CPU绑定的工作移动到 后台线程,但后台线程对进程没有帮助 只是等待结果可用。
我希望这个答案会增加一些细节,以便与你问题的其他回答一起使用。