两种方法让xamarin中主线程和工作线程的互动

刚接触xamarin, 就碰到了一个巨坑:在执行耗时任务时,主线程被阻塞,界面被锁死,即使在执行任务前,给了ActivityIndicatior.IsRunning=true都不显示系统忙的状态。于是花了一个多星期在浩瀚的海洋里寻找各种解决方法,终于在巨硬的一篇xamarin.ios的一篇文档中找到了参考:使用 Xamarin 中的 UI 线程 - Xamarin | Microsoft Docs, 文档用Thread和Task/Await实现了主线程和工作线程的互动,虽然这篇文档是写给IOS的,但实际上是关于线程Thread, Task/Await的,其他平台也一样适用。

我稍微修改了一下,在android上也实现了。几个关键的例程记录一下:

1. 耗时方法,写成同步方式

 private static List<string> ScanDevice(byte[] sn)
        {
            List<string> list = new List<string>();
            for (int i = 0; i < 4; i++)
            {
                Thread.Sleep(2000);
                list.Add("SerialNum " + i);
            }
            return list;
        }

2. 主线程更新UI方法

void UpdateUiState(bool isTaskRunning)
        {
            runningStatusLabel.Text = isTaskRunning ? "A task is in progress." : "All tasks complete!";
            defaultActivityIndicator.IsRunning = isTaskRunning;
        }

  这里更新了一个Lable控件和一个ActivityIndicator控件

3.Thread线程开启工作线程,并在工作线程中更新UI

void OnButtonClicked(object sender, EventArgs e)
        {//  可以更新UI
            UpdateUiState(true);//工作状态指示
            new Thread(new ThreadStart(() => {//开启工作线程并开始耗时工作
                var devices = ScanDevice(null);
                var text = "Devices = " + devices.Count;
                Device.InvokeOnMainThreadAsync(() => {//工作完成,更新UI界面
                    UpdateUiState(false);
                    DisplayAlert("info", text, "OK");
                });
            })).Start();
        }

  在工作线程中启用了Device.InvokeOnMainThreadAsync()操作线程。

4.Task/Await与UI互动,在await前后更新UI即可

List<string> mDevices;//用一个全局变量接收工作结果
        async private void OnTaskDemoClicked(object sender, EventArgs e)
        {//标记为异步方法
            UpdateUiState(true);//工作开始指示
            await Task.Run(() =>
            {//Task/Await方式,不需要在在子线程更新UI线程,但用了也没问题
                //Device.InvokeOnMainThreadAsync(() => UpdateUiState(true));
                mDevices = ScanDevice(null);
            });
            UpdateUiState(false);//工作结束指示
            var text = "Devices = " + mDevices.Count;
            await DisplayAlert("info", text, "OK");
        }

  我的理解,加了Await之后,程序在等待异步方法完成,也就异步方法变成了同步方法,UI的更新自然也就可以顺序执行了。

    我才疏学浅,刚开始接触Thread/Task/Await,很是晕菜,有个缺陷还没解决:耗时工作方法中的返回值,在异步执行中我不知道怎么接收,所以用了全局变量来接收。如果有知道的高手请留言告诉我,万分感谢。

  更新:“有个缺陷还没解决:耗时工作方法中的返回值,在异步执行中我不知道怎么接收”这个问题已经解决:

var devices = await Task.Run(()=>
{
    return ScanDevice(null);
});

 

posted @ 2021-09-14 16:30  CCJungle  阅读(635)  评论(1编辑  收藏  举报