笔记|Unity异步处理与UI Text显示的问题

探讨Unity3D中使用Socket TCP通讯时遇到的异步更新Text组件问题,分析协程与异步线程的区别,提供有效解决方案。

学更好的别人,

做更好的自己。

——《微卡智享》

本文长度为2323,预计阅读6分钟

前言

这阵子一有空就在研究Unity3D网络通讯,使用过程中访问通过协程的方式收到返回的数据直接更新Text的显示值都没有问题,结果在处理Socket通讯TCP方式采用异步时遇到了问题,本章主要就是记录一下测试的过程和处理方法,关于Unity3D与后台的网络通讯这块后面会有一个系列发出来。

遇到的问题


上图中可以看到,我们首先调用的是Restful正常的Get,Post的方法,获取到的数据在屏幕上Text的组件中也正常显示了。

再看我们使用Socket中的TCP通讯,当服务器发送数据过来后,上图中左下角的输入日志已经接收到了服务器发送的88878的数据,但是屏幕中的Text组件并没有更新显示。

先说明上面所有的网络请求后,返回更新显示Text的值都是用的同一个Action的委托方法

    /// <summary>
    /// 写返回Action的处理方法
    /// </summary>
    private void InitAction()
    {
        actionRes = new Action<bool, string>((bl, str) =>
        {
            Debug.Log(str);
            if (bl)
            {
                txtshow.text = str;
            }
            else
            {
                string resjson = "{\"array\":" + str + "}";
                _showstr = resjson;
                WeatherData lists = JsonUtility.FromJson<WeatherData>(resjson);
                StringBuilder sb = new StringBuilder();
                foreach (WeatherForecast item in lists.array)
                {
                    sb.Append("Date:" + item.Date + " Summary:" + item.Summary + " TemperatureF:"
                        + item.TemperatureF + "TemperatureC:" + item.TemperatureC + "\r\n");
                }
                txtshow.text = sb.ToString();
            }
        });
    }

问题排查

微卡智享

即然我们回调方法都一样,那我们就看看WebApi和Socket的通讯有什么不一样。

WebApi调用

上图中可以看到我们访问HttpRestful的Get方法里面是用协程的操作完成的,当请求返回数据后,直接调用action后就是我们前面代码的回调函数更新显示,接下来我们再看看Socket TCP的通讯。

Socket TCP通讯

上图中,我们使用Socket的TCP接收时,首先定义了一个TransData的类,把action传入进去,然后通过NetworkStream的BeginRead的方法进行处理数据接收。

TransData的类结构

上面几个图就是BeginRead中加入的回调函数,在接收完后我们直接调用transData类中的actionResult方法做后续的处理。

问题思考

不说两个方法接收数据后的处理,这里肯定都是一样的,最终都是把接收到的返回结果调用Action回调方法中执行,那问题会出来哪呢?

仔细再看了一个,在Restful的请求里面,我们用的是协程的方式处理的,而在Socket Tcp中,我们的BeginRead是一个异步的线程处理的,搜索了一下Unity中的协程解析,有这第一段说:

协程的作用一共有两点:1)延时(等待)一段时间执行代码;2)等某个操作完成之后再执行后面的代码。总结起来就是一句话:控制代码在特定的时机执行。

很多初学者,都会下意识地觉得协程是异步执行的,都会觉得协程是C# 线程的替代品,是Unity不使用线程的解决方案。

所以首先,请你牢记:协程不是线程,也不是异步执行的。协程和 MonoBehaviour 的 Update函数一样也是在MainThread中执行的。使用协程你不用考虑同步和锁的问题。

从上面这段话来说,协程不是异步执行的,所以text更新可以直接显示,而使用BeginRead时是异步线程操作的,做过多线程开发的同学应该都处理过线程与UI进行同步的问题(Andorid的开发可能更多),接下来我们就直接做个验证看看。

测试验证

我在Tcp通讯的Recv方法里面,使用BeginRead异步处理之前,先调用一下Action的方法,看看效果怎么样。

从上图中可以看到,在进入BeginRead之前,我们直接调用action的方法后,Text也是直接显示出来的没有问题了,这就验证了上面所说的问题,所以我们下一步就考虑怎么处理线程和UI同步的问题即可。

解决办法

微卡智享

其实找到问题后,解决这个的方法也更简单了,因为Unity中本身就有Update(),OnGUI()等方法,在每帧执行,所以我们可以直接把返回的数据做为一个内部变量,然后判断这个变量是否修改了,修改后再在相关的方法中更新Text即可。

01

加入更新显示变量

增加两个变量,一个是返回值保存到_showstr中,另一个是bool类型的,每当_showstr改变时,更改这个改变的值。

02

修改Action的赋值

修改Action的方法,把原来的txtshow.text赋值屏蔽后,改为返回的字符串赋值给_showstr,并且把_isshowstrupd的值改为True,用于记录当前显示值已经更新。

03

OnGUI中更新显示

然后在OnGUI方法中,判断如果_isshowstrupd为true时,修改txtshow.text的赋值更新,再把_isshowstrupd=false;

通过上面这几步就解决Text的显示问题了。

实现效果

扫描二维码

获取更多精彩

微卡智享

「 往期文章 」

Unity3D网络通讯(三)-- HttpRestful请求的简单封装

Unity3D网络通讯(二)--UnityWebRequest及JsonUtility请求Http Restful

Unity3D网络通讯(一)--Asp.Net Core WebApi创建发布注意事项

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vaccae

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值