编写桌面客户端的设计思考点
2015-09-19 18:15
141 查看
最近开始实习了,分配到的第一个任务时做一个基于C++的桌面客户端,由于开发的人员也都没有设计桌面客户端的经验,所以我最后来负责设计这个桌面客户端的架构,虽然最后的成品还是有很多瑕疵,但还是有一些可以借鉴学习的经验。
1 事件驱动模型
我编写过C++和JAVA的桌面客户端,两者都是基于事件驱动的。在JAVA中事件是交由EDT分配管理的,程序在接受到相应的事件的时候执行对应的操作。这个事件可以来自于用户操作,也可以由程序主动发出,如果我们需要进行异步操作,那么我们经常需要主动发出事件来与界面实现交互。
2 主线程
这一点在编写程序的时候我们需要明显,我们的界面显示刷新或者处理等事件响应操作都是在主线程执行的,所以我们可以确保事件响应是单线程的
3 异步数据获取
在初学客户端编程的时候我们可能经常会在比如按钮监听事件中尝试同步获取数据,然后刷新界面。如果应用是操作本地资源,那么这样的设计在一定程度上还是可以接受的,但是如果获取数据的事件过长,那么主线程便会被阻塞,直接效果是界面无法进行操作,如果此时在进行鼠标点击等操作,那么界面很可能出现未响应的情况。所以异步数据获取是一个必要的选择。异步数据获取之后数据怎么返回,这一点就需要用到之前提到的事件,子线程中通过事件来提醒主线程进行相应的操作。
4界面闪烁
普通的界面闪烁一般是因为某个组件在短时间内多次刷新,或者某个组件需要擦除刷新,组件擦除完成后过了一段时间主线程才处理刷新事件。减少界面刷新的主要途径是去除组件不必要的刷新,以降低组件的刷新频率峰值。有一种比较常见的界面闪烁的情况是我们在主线程中同时更新了2个组件,我们更新了一个组件的值,该组件的界面内容擦除了,该组件需要等到下一次刷新事件才能显示,主线程在修改另外一个组件的数据时花费了很长事件,等主线程执行完,界面获取一次刷新请求,所以第一个组件会出现明显的闪烁现象,解决的方案是将两个组件的更新分离,将一个事件拆成两个事件来解决。另外一种常见情况,该组件在短时间内被多次调用,比如我做的客户端有一个显示文件列表的功能,在文件上传时文件列表需要被更新,如果我们采用每上传一个文件就刷新一次的方案,那么我们批量上传小文件时那么界面就会出现疯狂闪烁的情况,我采用的解决方案是1采用守护进程,以一个固定的频率比如2s一次来接受后台产生的刷新事件,这个是采用信号量实现的。2使用增量式刷新,而不是擦除刷新。
目前存在的问题
1锁定界面操作
虽然我们可以通过异步操作空闲出主线程,但是此时的状态还是需要采用同步的状态,比如我们点击提交数据操作,通过异步处理,我们可以实现主线程以执行其他的操作(响应事件队列中的剩余事件),但是我们此时按照设计我们还是不应接受用户的输入的,比如我们切换了页面,调整参数等。我目前的实现方案是直接复用框架的接口,直接拒绝用户的输入,该种解决方案存在一个很大的问题是,我们无法再该过程中关闭或者放缩界面了,实际上这些操作是应该被允许的。第二种替代的解决方案是使用动态实现挂在的时候,我们在进行这种需要通过异步实现伪同步数据处理的情况时,我们通过移除不需要相应的事件表来实现拒绝用户相应的行为,这样部分我们允许用户相应的操作还是能被处理的。
2异步线程资源回收的问题
由于我现在获取数据的线程是采用分离式的线程,所以目前主要还是靠系统回收资源,当线程结束时或者是进程结束时自动回收,但是这样的方案肯定存在问题,目前没有找到好的解决方案
1 事件驱动模型
我编写过C++和JAVA的桌面客户端,两者都是基于事件驱动的。在JAVA中事件是交由EDT分配管理的,程序在接受到相应的事件的时候执行对应的操作。这个事件可以来自于用户操作,也可以由程序主动发出,如果我们需要进行异步操作,那么我们经常需要主动发出事件来与界面实现交互。
2 主线程
这一点在编写程序的时候我们需要明显,我们的界面显示刷新或者处理等事件响应操作都是在主线程执行的,所以我们可以确保事件响应是单线程的
3 异步数据获取
在初学客户端编程的时候我们可能经常会在比如按钮监听事件中尝试同步获取数据,然后刷新界面。如果应用是操作本地资源,那么这样的设计在一定程度上还是可以接受的,但是如果获取数据的事件过长,那么主线程便会被阻塞,直接效果是界面无法进行操作,如果此时在进行鼠标点击等操作,那么界面很可能出现未响应的情况。所以异步数据获取是一个必要的选择。异步数据获取之后数据怎么返回,这一点就需要用到之前提到的事件,子线程中通过事件来提醒主线程进行相应的操作。
4界面闪烁
普通的界面闪烁一般是因为某个组件在短时间内多次刷新,或者某个组件需要擦除刷新,组件擦除完成后过了一段时间主线程才处理刷新事件。减少界面刷新的主要途径是去除组件不必要的刷新,以降低组件的刷新频率峰值。有一种比较常见的界面闪烁的情况是我们在主线程中同时更新了2个组件,我们更新了一个组件的值,该组件的界面内容擦除了,该组件需要等到下一次刷新事件才能显示,主线程在修改另外一个组件的数据时花费了很长事件,等主线程执行完,界面获取一次刷新请求,所以第一个组件会出现明显的闪烁现象,解决的方案是将两个组件的更新分离,将一个事件拆成两个事件来解决。另外一种常见情况,该组件在短时间内被多次调用,比如我做的客户端有一个显示文件列表的功能,在文件上传时文件列表需要被更新,如果我们采用每上传一个文件就刷新一次的方案,那么我们批量上传小文件时那么界面就会出现疯狂闪烁的情况,我采用的解决方案是1采用守护进程,以一个固定的频率比如2s一次来接受后台产生的刷新事件,这个是采用信号量实现的。2使用增量式刷新,而不是擦除刷新。
目前存在的问题
1锁定界面操作
虽然我们可以通过异步操作空闲出主线程,但是此时的状态还是需要采用同步的状态,比如我们点击提交数据操作,通过异步处理,我们可以实现主线程以执行其他的操作(响应事件队列中的剩余事件),但是我们此时按照设计我们还是不应接受用户的输入的,比如我们切换了页面,调整参数等。我目前的实现方案是直接复用框架的接口,直接拒绝用户的输入,该种解决方案存在一个很大的问题是,我们无法再该过程中关闭或者放缩界面了,实际上这些操作是应该被允许的。第二种替代的解决方案是使用动态实现挂在的时候,我们在进行这种需要通过异步实现伪同步数据处理的情况时,我们通过移除不需要相应的事件表来实现拒绝用户相应的行为,这样部分我们允许用户相应的操作还是能被处理的。
2异步线程资源回收的问题
由于我现在获取数据的线程是采用分离式的线程,所以目前主要还是靠系统回收资源,当线程结束时或者是进程结束时自动回收,但是这样的方案肯定存在问题,目前没有找到好的解决方案
相关文章推荐
- oracle中execute immediate的使用(select/insert/update/delete)(转)
- 压力测试和性能测试的区别
- 在MyEclipse中快捷键的使用
- MBR&GPT
- sql查询第二大的记录(转)
- 对Git的理解
- 亿级Web系统搭建——单机到分布式集群
- Android SDK Manager中各个文件的作用-总结
- oracle安装分析
- com的主要接口介绍
- 自定义View构造函数参数理解
- 编写脚本实用工具
- underscore 笔记
- 自定义delegate模式
- 对git的认识
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- Atlas+keepalived实现mysql读写分离
- 细说Android drawable
- ListView和EditText发布帖子隐藏软键盘
- 43 Multiply Strings