All Stories
已经不记得有几个大年三十的晚上是在电脑前写代码度过了,今年破天荒的因为客厅里电视在放春晚,打偶然走过去看几眼。
今天把超链接处理模块重构了,之前那个实现在Mac下崩溃得比较频繁,但在Windows和Linux下却不是很多。对于这个现象我有点疑惑,虽然说代码确实是写得有问题,但为什么只有在Mac才比较明显呢。好在Mac下崩溃了打印出来的栈回调信息比较详细,几乎能跟踪到最终引起崩溃的代码行。
原来的实现把所有中间数据结构以指针的形式保存在一个list里,然后在自认为结束的时候销毁对象。这样的做法本没有什么问题,关键是我在操作这个list时并没有考虑重入的情况。于是重构主要做了两个重大修改,一是在list中直接保存对象,而不是指针,这样更不容易写错;二是对list操作大部分情况下都加mutex锁住。顺便也修正了些其他的小问题,比如原来即使是基于embed.ly的服务识别url是图片还是视频也有问题,其实embed.ly是返回了这个类型的。
另外,今天还把主界面针对360*640分辨率修改了一下,因为Nokia的S60v5和Symbian^3现在几个机型都是用这个分辨率的。至此,图片浏览特性的实现暂时告一段落,接下来该实现文章阅读了。昨天大致研究了一下Readability,发现它在Firefox表现那么风骚,结果在QtWebkit下总是返回不能分析的错误。不知道是DOM树的实现还是JavaScript引擎的问题。难道真要我移植一个C++版本,这实在太费时费力,还不好维护了。
最后,上个最新界面截图。
终于勉强加上了一个功能比较凑合的图片浏览功能,还有很多地方需要改善。本来我的想法是UI上直接拿QML Demo PhotoViewer的代码来用的,可是昨天发现PhotoViewer中的代码会导致在Windows下程序不能切换输入法,于是只好自己写了。自己写就极大地简化了功能,才简化了代码,于是最后所有东西都放在一个QML文件中写完了,最终的效果,也就是几个视图场景切换时那个动画效果没有了。残念!
另外有个问题是图片下载的问题,现在的Twitter上比较流行的图床大多是被墙的,如果让QML的引擎自己通过代理下载图片,感觉不是一般的慢!所以我就觉得把这些图片事先下载到本地缓存起来似乎挺有必要的。
还有个比较重要的问题是全屏模式下浏览图片,默认是自动拉伸到整个显示区了,这样似乎比较影响显示性能,当然也是机器配置不是那么好的才会有这种卡的情况,在我的T43上会卡,拿到Mac mini上就流畅了。应该稍微改一下,看一下是不是在加载前就获取图片本身的尺寸,如果比显示区域大,才缩放,不大的话,就以图片本身的大小显示了,这样显示也更清晰点。
还有个浏览某张图片的大图就不截了,没啥好看的。
有些问题,总是那么奇怪。因为XP里的虚拟机在跑Debian编译Qt,于是在Mac下把QML的Demo PhotoView抠过来用,本来就很吃力,还顺带发现了一个因为先后顺序问题引起的崩溃bug,终于可以在Ninayan里看到PhotoView的样子了。可是到了晚上突然发现,在Windows下不能切换输入法了,一切换Ninayan就挂死!经过一部分一部分地屏蔽代码发现,引起这个问题的似乎是VirtualDataModel中Package的一些代码。好吧,决定索性不用抠别人的代码,用自己的方法写一遍相同的UI吧。
上一段提到,我又蛋疼地在Debian里编译Qt了,嗯,又花了一下午。之后就是编译Ninayan,呃,我现在最大的乐趣就在于在不同的系统里编译Ninayan并用它来上Twitter了,囧rz。想来也不会有多大问题,毕竟之前在Arch和Mint里都比较顺利的,唯一大的区别是在Arch和Mint里桌面都是用Gnome,而这次Debian里用的是KDE,很花哨的感觉。言归正传,Ninayan运行得很顺利,除了字体不太好看。在Twitter上报怨了一下后,@truthurt建议自带一个开源的字体,真是个不错的主意,在Mint里的那种就很好,我后来去网上找了文泉驿的微米黑,在Debian和Arch里效果都很好。其实昨天就想过字体的问题,不过当时想到的是直接将字体装入到系统中,然后在程序中直接通过字体family名使用。今天偶然想到,其实可以程序直接载入指定路径的字体文件来使用的!不过Windows下还是用微软雅黑吧,微米黑在XP下同一个字的不同笔画都有粗细差异,真糟糕。
今天照计划,实现了查看对话的功能,不过不完善,因为网络传输的原因,是一条消息一条消息从服务器获取后显示,如果显示到一半切断,又要显示另一组对话,就会把前一组对话后面没显示的那些消息作为后一组对话的消息。所以要考虑一下怎么加一个中断的机制,不过这个留到以后版本中完善吧,毕竟Ninayan一开始定位就不是一个完善的客户端。
然后又蛋疼地去装ArchLinux了。这个发行版安装比Ubuntu麻烦多了,它的iso镜像只装一个最基本的字符界面,然后带一个pacman包管理工具,GNOME之类的桌面需要自己再另外安装,所以最好有比较畅通的网络。
装完后,中文字体的显示惨不忍睹,google随便搜了一下,也挺折腾的,我懒得弄了。我就是想在上面试试编译Ninayan。没想到可以用pacman安装已经编译好的Qt 4.7.1,再装个Qt Creator,就可以编译Ninayan了。除了显示的字体不好外,其他的还算凑合吧。
明天开始做图片浏览和文章阅读功能吧。
昨天和前天晚上蛋疼地在Linux上编译Ninayan了。我用的是Mint9,也就是一个Ubuntu的修改版。在Linux上编译Qt程序有点麻烦的是需要自己编译一遍Qt,前天晚上就编译了一遍最新的qt-everywhere-opensource-src-4.7.1.tar.gz,过程比较顺利,再装上Qt Creator就可以编译出Ninayan了,简单试用了一下,很正常。而且令我比较惊讶的是,我学Hotot用了Droid Sans字体,最终的显示效果在我个人看来比Windows XP SP3和Mac OS 10.6.6上都要好,但XP SP3上加上Gdipp或MacType后,效果会有很大的提升。
昨天突然发现,Ninayan在Mint下不能访问https://api.twitter.com(不是被墙的缘故),测试了几次才确认是不能访问https的地址,于是想到前不久看过一篇博文说Qt 4.7是有这么个bug不能访问https的,因为原来Qt 4.6带了SSL证书,而Qt 4.7没带,于是照那篇文章的作者的说法,从Qt 4.6.2里找到qt-ca-bundle.crt文件,然后每次QNetworkRequest在被post或get前都设置一下Ssl证书。结果我的情况是连编译都不通过,于是可以确认是Qt在编译时没有编译进OpenSSL了。然后找到了这篇《Compile Qt 4.7 on Ubuntu 10.10》,先要安装一堆的库的开发包,再来编译Qt,最后再编译Ninayan,果然就正常了!于是我就不明白那篇博文讲述的到底是个神马问题了!
今天就比较烦躁地在做网址缩短功能了。本来打算内置goo.gl,bit.ly和is.gd三个短网址服务,结果很郁闷的是bit.ly总是返回INVALID_URI,但同样的URL我拿到Firefox下测试就能返回正确的数据,这不是歧视嘛,难道是在http header里还要设置神马东西?倒是goo.gl和is.gd都正常了!
话说前天偶然发现了MacType和Gdipp,觉得这种功能对Ninayan之类偏阅读的应用非常有帮助,于是我在极限论坛上给MacType的作者私下发了个email询问是否可以提供专门的API以便集成此功能。不过到现在也没收到回应,估计是不愿意了。
今天看了一下MacType的安装目录,发现有个MacLoader.exe,而Gdipp的安装目录下也有个loader文件,这时才明白过来,可以通过把可执行文件的完整路径作为命令行参数传递给这loader,那么该可执行文件会被启动运行,并被注入实现字体渲染增强效果。
经过简单的测试,Ninayan在我的XP SP3上使用微软雅黑字体,加上增强字体渲染效果,感觉确实更舒服了!而Gdipp是以GPLv3,最新的版本好像是用LGPL了,一起打包发布应该是木有问题的。我只要另外再写一个小小的启动程序,在安装包中把启动程序作为快捷方式添加到开始菜单和桌面等位置,可以自己调整是否使用增强字体渲染效果,使用什么样的渲染配置等等。
这样一来,似乎Windows上的效果都超过Mac上的了,一直没找到感觉特别好的Mac上的用于大段文字阅读的字体,微软雅黑只适合在Windows上用,而且至少要开了ClearType Tuner才行,有MacType或Gdipp最好。也许是因为我在Mac下用的是CRT的显示器的缘故,不止一个人对我说过那个视频信号转换后损失挺大的,也许用LCD的就要好些了!
今天心情不错,呼呼!
前面说到内存泄漏的问题。后来通过逐段屏蔽代码,终于找到了最大一处泄漏源。这个办法比较笨,但这次真的有用,主要还是因为程序结构简单,流程也不复杂才能用吧。
程序大体上分为三部分,UI层,数据层,网络通信层。用户在UI层上操作,1、UI层向数据层请求数据,2、数据层根据不同情况直接查询本地数据库或通过网络通信层获取数据,3、网络通信层自己有一个定时轮循的任务,每分钟从远程服务器获取数据,4、有了数据就发送给数据层,5、数据层将数据经过简单处理发送给UI层,6、然后显示,就是这么简单。
我开始主要怀疑UI显示调用的Qt/QML也许MM有问题,于是把最终UI显示的代码屏蔽掉。发现仍然泄漏的情况基本没有变化,说明跟UI显示的关系不大。后来发现Mem Usage的增长是有周期,大概是1分钟1次,那么可以确定是在4和5两步有问题。这时把第5步中代码全部屏蔽掉,果然Mem Usage就不增长了。然后逐步缩小范围,一点点放出代码,最后发现竟然是QSqlQuery查询本地数据库时,select出来的东西需要程序员自己clear掉!内牛满面啊,果然是Qt用得有问题!
今天偶然发现一个叫MacType的东东,可以在Windows下以进程注入的方式给指定进程增强字体渲染效果。跟微软官方的ClearType Tuner是一类东西,不过MacType的选项更丰富。于是我想到,我这个以阅读为主的工具,要是集成这么个美仑美奂的功能,该是多酷啊。在极限论坛翻了一遍帖子,貌似MacType是闭源的,另外有个新生的Gdipp项目,倒是在googlecode上开源了,不过听说它的配置复杂,而且目前不够稳定,尤其是32位系统上。好吧,反正这种功能对我有致命吸引力,一定要集成!
内存泄漏的问题,调得我心力交瘁,都有点神经衰弱了,甚至有点绝望,唉。以前还真没有过这种强烈的负面情绪出现过。
每次UI刷新,从任务管理器里看Mem Usage都会增加2-3MB,这得有多严重的泄漏啊!可是我自己的代码中new出来的对象都经过跟踪是销毁掉了的。于是又把矛头指向Qt内部,或者是QML中了。
本来怀疑是QML中的实现可能有问题,于是把Qt从4.7.0升级到4.7.1,貌似泄漏得更严重了。所以现在都已经不敢怀疑是Qt有问题了,开始怀疑是没有遵循Qt的用法。有些Qt返回的东西,需要程序员来负责销毁,比如QNetworkAccessManager在调用get或post后返回的QNetworkReply对象,这是多么操蛋的设计啊,指不定就是每次在哪里它自己创建出一堆对象出来要我来销毁我却不知道呢!
从CodeProject上下载了个Visual Leaks Detector,从说明上看,说是在msvc的jit debugger里会自动打印信息到debugging output window里的,可我实际上试了之后,发现屁都没输出一句,难道它是for MFC-based project only的?有可能的,唉!
简直走投无路了。
本来排除在计划外的事情,今天又去搞了,就是支持Twip4。前一天也折腾过一下,没弄好,这回问了一下Twip4的作者@yegle,他开始说是计算数字签名时用https://api.twitter.com/作为base string就行了。我试了下不行,后来他又说试试T模式吧,有几个客户端是经过实践T模式没问题的。于是一下子就明白过来了。 Twip4有T模式和O模式两种工作模式。T模式是完全的透明转发,Twip基本上不做任何处理,所以要请求oauth token和oauth token secret时原本是向https://api.twitter.com/oauth/access_token请求的,同时也是拿https://api.twitter.com/oauth/access_token作为base string计算数字签名的,在使用T模式的代理时,只要向http://www.myproxy.com/oauth/access_token请求就行了,仍然用https://api.twitter.com/oauth/access_token作为base string计算数字签名,这样就能无障碍获取oauth token和oauth token secret了。至于O模式,我看了下TweetDeck和Mixero的表现,发现它们也并不向O模式Twip请求oauth token和oauth token secret,或者请求了也没结果。所以我就推测其实O模式是没这功能的,O模式自己有consumer key和consumer secret,所以自己有一套oauth token和oauth token secret,但不是给客户端用的,即使客户端用自己有效的oauth token和oauth token secret发送给Twip请求,Twip也会把http header和url parameters里的东西处理一遍,用自己的那套oauth token和oauth token secret计算出来的东西替换掉。所以我想如果用O模式也要让用户可以无障碍认证的话,需要软件自己提供一个透明代理,软件先拿用户名和密码从那透明代理处获取oauth token和oauth token secret,然后在其他发布消息,收取消息时用O模式代理,就可以解决这个问题了。...