zoukankan      html  css  js  c++  java
  • 两种方法让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);
    });
  • 相关阅读:
    异常
    C++中的mutable,volatile,explicit关键字
    Vi配置文件--Vimrc
    结构体和类的区别
    [转]恢复视力的方法(500度以下)
    与struct相关的宏定义 ---今Tencent笔试用到的
    如何在C++中调用C的代码
    C中如何调用C++函数?
    技术博走起
    Shell常见命令实践
  • 原文地址:https://www.cnblogs.com/ccjungle/p/15268237.html
Copyright © 2011-2022 走看看