Google Android UI之困境:统一还是分化

Android 的 UI 话题,恐怕是Google 和OEM制造商之间的一个主要冲突。本文作者Ben Hookway是一家视频公司的CEO ,他分析了Google未来的UI 战略以及发展趋势。

用户界面(UI)的话题,总是会带来强烈的争论。这有点像电视领域——每个人都是专家,因为每个人都是用户。 早在 2002 年,那时候的电信运营商就有一套自己的 UI 定制界面——例如Vodafone Live 和Orange SPV。当然,这遭到很多OEM 制造商的反对,应为制造商往往希望在产品中突出自己的品牌,而不是运营商的品牌。 OEM 制造商的困境 所以3 年过去了,OEM 制造商都只是在 Windows Mobile 和Symbian 手机界面上小幅改动,而不是按照运营商的要求创造一套新UI。同时,运营商也看到,自己定制 UI 并不能得到期望的回报,所以这事儿就散了。 随 着 2007 年 iPhone 的爆发,UI 又重新成为了最热门的话题。iPhone 成为了标杆,几乎所有 OEM 制造商都努力开发自己的 UI 界面——它们被称作 HTC Sense ,Moto Blur,Sony Ericsson Rachael,三星 TouchWiz , LG S-Class。 此时,运营商试图组建更庞大的团队来研究和控制手机 UI 。Vodafone,Orange 和 T-Mobile 都投入了 100 个以上的人力来研究和定制 UI 。这股潮流也蔓延到了大洋彼岸,Verizon 和 AT&T 也投入了数百万美元建立相关的研究所。 这也促成了一些专业的设计公司和产品,例如 TAT Cascades 和 Mentor Inflexion 。 最新的传言是 Google 将严格控制 Android 的 UI,让不同厂商的设备提供统一的界面。这将改变目前 Android 阵营的零散状态,避免很多因为厂商定制 UI 而引发的问题。 然而,这对 Google 的合作伙伴来说不是一个好消息。冲突的核心是,Google 希望像苹果那样获取更多的控制权限,控制硬件指标,控制软件性能,控制内置服务。 当然,苹果和 Google 的商业模式大不一样。 苹果能够从芯片,外观,软件,广告,服务,到品牌,渠道,零售价格做到全程控制,而 Google 做不到,它只控制软件。 苹果能够按照自己的节奏,每年发布一款新机。而 Google 的合作伙伴每年生产一百款新机。 苹果投入很多广告,把旗下多款产品建立起一个统一的品牌。Google 很少为自己的合作伙伴产品投放广告。 最重要的是,Google 必须依赖于 OEM 制造商,才能制造出产品。 OEM 的世界里,竞争激烈,生存条件恶劣,利润稀薄。价格和 UI:这两个因素几乎都被制约了——价格被 ODM 厂商制约,UI 被 Google 制约(即将制约)。 在以前, OEM 厂商要玩转这个游戏,就必须发展差异化 UI,而现在 Google 即将把这点权利给夺走。Google 不切实际地走向了苹果的商业模式。 这只能让事情越来越糟。 横跨四个屏幕的战争 接下来的战斗将蔓延到你的整个生活——不止是手机,还要加上电视,电脑,平板。由多屏幕组成的“用户体验生态系统”(Experience Ecosystem),能让用户把操作经验和习惯轻松地由一个屏幕过渡到另外一个屏幕。 浏览器已经缩小了笔记本电脑,手机,电视和汽车的距离,而“App”即将采用这种模式发展。 如 果要让手机,电视和电脑无缝连接起来,需要一个“统一”的用户体验。苹果在这里又成为了典范:Mac ,iPhone ,iPad 都采用类似的手势和操作方法,而且还形成了一套应用程序的设计指南。更何况还有 iTunes 和 MobileMe 云服务,这些元素凑在一起组成了第一个“用户体验生态系统”(Experience Ecosystem)。 而在 Android 阵营里,Google 最近发布了 Google TV。所以要在手机和电视上提供“统一”的用户体验,将是一件最重要的事情。如果你看到手机制造商把触角延伸到数码相框,无绳电话,机顶盒等产品,千万别感到惊讶。 控制硬件的一致性,将有利于完善 UI 响应和画面质量。但是,Google 能达到苹果那样的硬件一致性?Android 的下一个版本就是一次尝试。 围绕 UI 的争论将愈演愈烈 想象一下吧,你购买了基于 Android 的平板和电视,它们能相互同步播放视频节目。浏览器已经提供了这两种平台上的用户体验一致性,但其他很多程序做不到。 随着厂商的增加,设备的增加。围绕 Android UI 的争论不会消失,而是会越来越激烈。 OEM 制造商需要利用差异化的 UI 来提升自己品牌的忠诚度,构建自己的“用户体验生态系统”。但上升一个层次,Android 整个集团也需要一个“用户体验生态系统”来维护集团的利益。 Google 是接受 UI 分化的现实?还是从根本上改变这个市场?它会怎么做?

Android:Activity中onCreate方法的参数及用途

写过Android程序的都知道Activity中有一个名称叫onCreate的方法。该方法是在Activity创建时被系统调用,是一个Activity生命周期的开始。可是有一点容易被忽视,就是onCreate方法的参数saveInstallState。因为在一般的程序开发中,很少用到这个参数。 onCreate方法的完整定义如下: `public void onCreate(Bundle saveInstallState){ super.onCreate(saveInstallState); }`     从上面的代码可以看出,onCreate方法的参数是一个Bundle类型的参数。Bundle类型的数据与Map类型的数据相似,都是以key-value的形式存储数据的。     从字面上看saveInstallState,是保存实例状态的。实际上,saveInstallState也就是保存Activity的状态的。那么,saveInstallState中的状态数据是从何处而来的呢?下面我们介绍Activity的另一个方法onSaveInstallState。     onSaveInstallState方法是用来保存Activity的状态的。当一个Activity在生命周期结束前,会调用该方法保存状态。这个方法有一个参数名称与onCreate方法参数名称相同。如下所示: `public void onSaveInstallState(Bundle saveInstallState){ super.onSaveInstallState(saveInstallState); }`     在实际应用中,当一个Activity结束前,如果需要保存状态,就在onSaveInstallState中,将状态数据以key-value的形式放入到saveInstallState中。这样,当一个Activity被创建时,就能从onCreate的参数saveInstallState中获得状态数据。     状态这个参数在实现应用中有很大的用途,比如:一个游戏在退出前,保存一下当前游戏运行的状态,当下次开启时能接着上次的继续玩下去。再比如:电子书程序,当一本小说被阅读到第199页后退出了(不管是内存不足还是用户自动关闭程序),当下次打开时,读者可能已忘记了上次已阅读到第几页了,但是,读者想接着上次的读下去。如果采用saveInstallState参数,就很容易解决上述问题。

罗马不是一天建成的,我们一直在努力-关于DataCross

DataCross是一个数据格式转换工具,致力于为Java项目提供可靠,方便的格式转换服务;提高项目开发效率,降低项目开发成本。     DataCross源自于实际,以前工作中经常将数据从一种格式转换成另一种格式,次数多了就想能不能做成一个通用性的工具,这样以后再有这类数据格式转换工作时,就可以攻玉直接参与使用了,而不必将原来的许多代码重复多次,基于这样的想法,开始了datacross项目,DataCross和所有的开源项目一样,是一个不断完善的过程。比如开始时,将建立数据库连接等操作都包含进datacross中。后来在另一个场合发现不太通用,所以去掉了数据库连接功能,数据库连接由外界调用程序员提供。再比如开始时,想到了数据过虑,就是从Reader中读取数据时,判断是否符合条件。只有符合条件的才能读取出来,后来发现也不太实用就去掉了。所以这个项目是一个不断完善的过程。在完善过程中,我会考虑版本的向后兼容性。保证不修改用户程序就能升级datacross的jar包。     datacross能将数据在XML,数据库,Text,Excel,SQL,JSON等格式间相互转换,要求数据必须是矢量数据,也就是说一批数据中的每两组数据的结构相同。     datacross具有广泛的使用价值。比如:将数据中的表用datacross导出成xml或其它格式的文档离线存储起来,就能实现数据库的备份,一旦需要还原也可以使用datacross直接从xml或其它格式的文档中提取数据到数据库中。比如两个异步的系统之间要同步数据,可以用datacross将数据从一个系统中导出成一种共用格式的数据文档,然后将该文档送到另一个系统中,再用datacross导入。再比如说,现在的信息系统一般要用到许多的报表,只要你给出一个合理的SQL语句,就能将报表数据导出成Excel,html等格式的报表文档中。 项目地址:[http://datacross.daahe.com/](http://datacross.daahe.com/)

Flex弹出页面不能监听到主程序中的事件

用PopupManager.createPopup弹出窗口后,不能在主应用中监听到弹出窗口中的事件。因为,从PopupManager.createPopup() 创建的显示对象DisplayObjects 不是application的子类,按照冒泡事件特性,当然添加在application对象的监听器就没法捕获此事件了。 要解决这个问题,我们需要了解一些FLEX的框架,如下图所示: 从这张图,我们可以清楚的看出,FLEX应用程序的弹出框不是application容器的子类,而是systemmananger的子类 因此在flex中我们捕获popup的事件应该这样来做: this.systemManager.addEventListener(AuthonSuccessEvent.AUTHON_SUCCESS, onAuthonSuccessHandler);

360 VS QQ:一场精心策划的西安事变(上)

本文来自CSDN特约评论员:徐三清 我一向将公司比喻成国家,公司之间的竞争也很类似战争,国外网站曾经有一幅描述微软帝国的作战形势图就是例证。这次360和QQ之争,在中国软件互联网史上,是一场不折不扣的超级大战。我对这场战争的分析是:一场精心策划的西安事变。 一)作战双方进行分析


进攻方360系(安全卫士系列) 主帅:周鸿祎 版图: 按照3.5亿网民算,2.4亿安全卫士装机量,覆盖互联网人口70% 军队:数百名 精锐部队是Windows系统核心高手,主帅曾说360旗下已网络全国近一半高手 装备:360安全卫士,360浏览器,360杀毒 经济力:收入3亿,利润1亿,估值数十亿元 敌对方: 安全系(金山,瑞星,江民,可牛,卡巴斯基) 浏览器(搜狗,傲游) 恩怨(百度系,阿里系) 同盟方: 迅雷和其他周鸿祎投资的软件公司 历史战役 > 2002 以3721击败CNNIC。 > 2005 以一搜(3721)和qihoo社区搜索进攻搜索,败于百度。 > 2006 推出360安全卫士,清除专门用于扫描被安装在用户电脑上的一切“恶评”软件,包含前身是3721上网助手的雅虎助手。此举深受用户欢迎,360安全卫士 也因此在短短2年之内成为市场占有率第一的个人网络安全软件,但因此也和Yahoo杨致远,阿里巴巴马云结下了仇。 > 2007 与卡巴斯基结盟,借其杀毒技术扩展市场,360同卡巴斯基绑定推广。但随着2008年360推出免费杀毒产品后,双方开始刀剑相向,结为仇敌。 > 2008 挑战瑞星。瑞星炮轰360欺骗用户。随后两家公司激烈谩骂,最终不了了之。 > 2010 5月出兵金山,封杀“金山网盾”。周鸿祎连发几十篇微博,“揭露”金山造假, 导致金山股价大幅下跌。 优势: 主帅周鸿祎:作战能力超一流,口才在中国IT界超一流; 技术团队实力超群,特别是windows客户端核心系统技术在中国超一流; 产品运营能力彪悍,从3721到360卫士其客户端装机发展速度在中国是No.1。 劣势: 树敌无数,和历史的合作方,以及中国最主要的互联网公司都结下了巨大的恩怨。 作战特色: 以“免费”和“安全”为大旗,通过360安全卫士占领用户的桌面,成为仅次于QQ装机量的软件客户端。以安全卫士为大本营,推荐安装360系列家族软件,最具杀伤性的武器是提示竞争对手的软件可能存在缺陷,并以此为利器,迅速夺取了浏览器20%的市场份额。 防守方腾讯系 主帅:马化腾 版图:10亿注册用户,覆盖互联网人口95%以上 经济力:年收入124亿,年利润52亿,估值3500亿元 现金60亿元 装备:QQ,QQ管理专家(QQ医生),TT浏览器,QQ旋风下载,QQ影音,QQ Mail,QZone,QQ.com,QQ游戏等 军队:近万名 旗下大将如云,精锐部队来自微软Windows 和MSN团队 敌对方: 游戏系(盛大,联众) 门户(新浪,搜狐,网易) 搜索(搜狗,百度) 电子商务(阿里巴巴) 社区(人人,开心网,51) 软件系(迅雷,快车,暴风影音) 浏览器(搜狗,傲游) 同盟方 金山、可牛等 历史战役 > 2002 以OICQ(QQ)击败UC。 > 2004 www.qq.com 挑战新浪、搜狐、网易,成为中国最大的门户网站之一。 > 2006 推出超级旋风,挑战迅雷。 > 2006 推出拍拍,挑战阿里系的淘宝。 推出搜搜,挑战百度 推出QQ医生,进入杀毒软件市场 > 2007 以QQ拼音输入法挑战搜狐。 > 2009 QQ Mail挑战网易163成为最大的免费邮件提供商。 > 2010 年初小游戏平台3366.com上线公测,进攻4399小游戏平台。 > 2010 QQ团购网上线,进军团购市场。 > 2010 推出SNS社区“朋友社区”,剑指人人、开心。 优势: “挟天子(用户数)以令诸侯”。腾讯拥有中国本土用户量最大的即时通讯软件,账户数近10亿;也是中国最赚钱的互联网公司,公司现金储备达到15亿美元;再加上实力雄厚的研发和营销团队,强大的地方政府支持,足以使其傲视天下。 劣势: 通过QQ庞大用户群,采取后发模仿的方式扩展自己的领域版图,其“一站式在线生活”战略,在软件和互联网界树敌无数。 主要战术: 通过QQ庞大用户群,采取后发模仿的方式扩展自己的领域版图。最强的核武器是QQ弹窗和升级捆绑。腾讯的战略手法是模仿和后发制人,先看着其他人争夺地盘,看清楚了,地盘够大的地方,再派QQ系进驻。 二)战争起因


周鸿祎是互联网界的枭雄,作风彪悍,出言无忌,他对互联网产品和运营有极高洞察力,口才极具魅力,论主帅单挑能力,排名第一。他最遗憾和郁闷的是败给百度的帅哥李彦宏,“我是真小人,他是伪君子”。某次做公开的性格测试时,他表示最痛恨的人就是李彦宏。 他的目标是成为中国互联网领域的老大,当然要完成这一目标,必须建立自己的地盘。小马哥通过QQ一统IM,搜索已被李帅哥牢牢控制,电子商务被马怪侠掌握,门户则有新浪老大的地位不可动摇。 周鸿祎经历了搜索之战后,意外发现了安全软件这一块大好领土,但要想称霸互联网,光执掌安全市场之牛耳还不够,必须成为中国最多用户群体的的入口。周最推崇有两本书《柔道战略(小公司战胜大公司的秘密) 》和《免费:商业的未来 》。 所谓柔道战略就是避其锋芒、放弃硬碰硬的竞争思维模式,成功的挑战者不是去硬碰硬,而是利用对手们的块头和力量将他们打倒。这就是柔道战略的核心思想。 于是周相继推出软件管理、浏览器,挟安全卫士的庞大用户基础击败各个对手,“免费+安全”是他的杀手锏 ,类似于“打土豪,分田地”这些对用户极具诱惑力的口号,效果颇佳,成功地打败了一个又一个靠软件收费的地主老财。 直到碰上腾讯,周鸿祎迎来了真正的对手。腾讯不仅有着跟周鸿祎一样的王霸志向,更为重要的是,它已经具备了称霸互联网的实力和基础:用户群、资金、 技术、人才、政策……同样,一山不容二虎,腾讯也视周鸿祎为肉中刺,2010年5月31日,随着腾讯的QQ医生3.3升级版——QQ电脑管家悄然上线。人 们很快发现,这款原本只是用来查杀QQ盗号木马的防护软件,已经包含了云查杀木马、系统漏洞修补、实时防护、清理插件等多项安全防护功能,甚至还搭载了免 费半年的诺顿杀毒。 无疑,这是一把利剑,直捣周鸿祎的黄龙。让人想起了30年代,蒋介石命张学良率军直击喘息未定的中共心脏——延安。但周鸿祎却非腾讯原来的对手可比,仔细观察周鸿祎公司近期的举措不难发现,他们正在精心谋划一场互联网“西安事变”。 前期战争 2010年年初,腾讯突然选择在二三线及以下城市,强行推广QQ医生安全软件,并迅速占据国内一亿台左右电脑,市场份额近40%。敏感的360很快 意识到威胁,迅速召回正在休假的员工,快速反应。由于QQ医生本身匆忙上阵,很多用户陆续卸载QQ医生,其市场份额也快速降至10%以下。360初战告 捷。 3个月之后,腾讯发布更加强大的QQ医生升级版QQ电脑管家,正式与360安全卫士展开直接竞争。360此时正在与金山激战,一时措手不及。 如果说2010年年初腾讯启动安全领域的闪电战,周鸿祎在感受到腾讯的威胁,以及恐怖的爆发力时,也许还心存侥幸,认为腾讯并没有把他当作主要对 手,毕竟在整个互联网产业链四处扩张,一向是腾讯的惯性。但QQ医生5月的突袭,显然会使得周鸿祎放弃所有幻想——QQ预置360于死地早已酝酿许久。 QQ与360之间必有一场生死之战。 那段时间,周鸿祎在接受一次媒体专访时,建议腾讯应该加大投入解决QQ内部安全问题。联系到4个月后针对QQ安全性的“隐私战”,可以推测,此时周 已经在设计针对QQ的“西安事变”了。而QQ今年中秋时期的又一次针对360的突袭,直接形成本次事变的导火线——腾讯宣布“QQ软件管理”和“QQ医 生”自动升级为“QQ电脑管家”,涵盖了安全防护,系统维护和软件管理等功能,而这也是目前360安全卫士的主流功能。而凭借着QQ庞大的用户基础,QQ 电脑管家将直接威胁360在安全领域的生存地位。 周鸿祎必须要出招了。

360 VS QQ:一场精心策划的西安事变(下)

第一阶段:预设伏兵——隐私战 9月27日,360发布直接针对QQ的“隐私保护器”工具,宣称其能实时监测曝光QQ的行为,并提示用“某聊天软件”在未经用户许可的情况下偷窥用户个人隐私文件和数据。这引起了网民对于QQ客户端的担忧和恐慌。360成功地打胜了一场用户心理战,而这一切,还都是序曲。 第二阶段:挑衅羞辱——扣扣保镖导弹轰炸 10月29日,360宣布推出一款名为“扣扣保镖”的安全工具。360称该工具全面保护QQ用户的安全,包括阻止QQ查看用户隐私文件、防止木马盗取QQ帐号以及给QQ加速等功能。 从扣扣保镖的功能看,显然是蓄谋以久,不是一朝一夕能开发出来的,而且“精确制导”,可禁止启动QQ秀、QQ会员等数项其社区增值服务的最核心来源,近乎直接卡死了腾讯的生存法门。同时选择马化腾生日这一天开战,无疑也表达了对对手的“蔑视”。 这看上去是一招真正的杀手锏,不仅可重击对手、扩大市场空间,甚至还可以借“安全”为名,名正言顺获得QQ的用户资源,以更加全面、深入地瓦解QQ帝国的用户基础。 但根据目前战情的变化来看,“扣扣保镖”的导弹轰炸,还只是“虚晃一枪”,并不是周鸿祎的真正后手,他并没有把宝压在这颗导弹上。他主要是想用这种道德上“痛打落水狗”、市场上“直挑对方老巢”、近乎羞辱般的方式,激怒腾讯。 果然,11日4日上午的腾讯新闻发布会上,公关经理刘畅以泪洗面,哭诉腾讯上下全体员工正在经历10多年来最惨烈的一次遭遇……周鸿祎的战略目标达到了,因为一个人在倍感羞辱、泪眼交加的时候,往往会做出丧失理智的反应——腾讯真的祭出了它的核武器。 第三阶段:引蛇出洞——腾讯核武器反击 以泪洗面的腾讯宣布了“一个艰难的决定”,在装有360软件的电脑上停止运行QQ软件,这是360与腾讯一系列争斗中,腾讯方面迄今为止最激烈的行 动——腾讯自己的定义是“惨烈行动”。此举立刻引起震动了整个业界,腾讯也由此陷入了网友口水的汪洋大海中,因为腾讯这一核反击,客观上是以牺牲用户利益 为代价的,腾讯一下子失去了“道德制高点”,同时腾讯此举表现出的潜在垄断竞争能力,也令业界人心惶惶。令人瞠目结舌的是,周鸿祎几乎第一时间通过微博表 态称自己早有预案:“对于腾讯这样丧心病狂的行为,360有预案。我们推出了WEB QQ客户端,该款软件可以保证用户既能顺畅的聊天,同时也能避免被QQ软件偷偷扫描硬盘。”11月4日,在腾讯解释其“惨烈行动”的同时,周鸿祎高调宣布 召回扣扣保镖,然后中午时分又以一副谦谦君子般的姿态,通过公开信表示决定搁置争执,向受影响用户致歉。也许此时,才能看出周的真正目的,他其实打的是一 场道德之战、争夺“人心”之战,并置腾讯于亿万网友的对立面。 第四阶段:后续战火—— 11月4日,工信部电信研究院相关负责人向记者透露,针对此次360和腾讯纠纷的工信部官方调查程序正式启动。11月5日上午工信部电信研究院会 召开专家会议,对此事进行讨论。几乎同一时间,金山、搜狗、傲游、可牛、百度联手举行发布会,表示五家厂商的客户端软件将不兼容360系列软件。但蹊跷的 是,会议临近结束时候,搜狐张朝阳突然在其微博上说“据我所知,搜狗没有与360不兼容的计划”。 综合整个战役,也许无论腾讯还是奇虎,都没有料到这场发生在两个厂商间的互联网争夺战,会闹出如此大的局面,产生如此大的影响。 四)战略分析


1. 腾讯的核武器反击是否得当 腾讯目前采取的反击策略:让用户进行二选一,涉嫌利用垄断强制推广,涉嫌单方面违约,结果也是骂声一片,为什么腾讯会采取这样一看就不好的策略?导致杀敌一千,自伤八百? 反过来替腾讯考虑还有什么手段?扣扣保镖直接掐住了腾讯的收入线,腾讯必须短期反击挡住这一攻击。策略大致有四种,一是诉诸法律,但对于软件外挂的 界定目前还缺乏标准,法律的制裁周期也较长,而且还难以保证实施;二是技术反击,一种策略是开发防守工具,不允许扣扣保镖修改。另一种策略是开发反攻工 具,清除扣扣保镖。但这两种策略都会和360在用户的电脑上形成攻防拉锯战,因为360同样拥有一批技术高手,在技术战争中还从没失败过。三是提醒用户, 并让用户选择。四是强制用户选择。 短期最有效,而且最有杀伤力的就是第四种,这也是腾讯最后的选择。 这个选择虽然非常有效,但带来的震动太大,这次用过,以后碰到类似危机再次使用这种核武器的几率非常小,也就丧失了打击对手最强大的威慑力。 2. 预测结果 预测结果:在政府的强行介入下,行业协会将组织建立行业联盟,对于隐私权和软件外挂将制定相应的规则,使得同类手法的战争不会出现。360和QQ将退回9月底的状况,暂时保持在用户电脑上的和平共处。 但争夺用户桌面入口的暗斗、在用户电脑上的软件战争将不会停止。 这场战役到目前为止的战况结果分析是:对360来说,长期来看会获益于得到为用户服务的好名声,提升360的品牌和影响力。但短期内360系软件市场份额直线下降,其他竞争对手包括搜狗浏览器,金山瑞星杀毒软件得到发展机会。 对腾讯来说,短期来看腾讯灭掉扣扣保镖,避免了一场强大对手攻击的危机,并成功削减了360的地盘。但长期来看动用捆绑用户的核武器,失去民意,如 果360联合其他对手卷土重来,推出360系聊天工具,可以导出QQ的好友和群关系(技术专家云风已经给出解决方案),腾讯将面临下一次的重大挑战。 由此也可以看出,虽然这场政变蓄谋已久,但发动时机还是欠妥,360手上并没有马上推出IM的工具,也没有联合可能的盟友(飞信,天翼,MSN,新浪UC),也许笔者猜测失误,360聊士近期很快推出,口号还是免费+安全,那真是要佩服老周的谋略了. 不管怎么说,360vsQQ的大战极大地提高了360和周鸿祎的知名度,原来在IT界他是响当当的人物,但对于全社会非IT人士和政府人士来说还所知有限,但这次作战正像当年的西安事变一样,一战威名扬天下。 最新动向 11月5日晚,向来在媒体上低调不露面的的马化腾公开接受了《经济观察报》的采访,360 攻势太猛,”从上周五上午360公司11点多发布到周一,就已经有2000多万用户感染扣扣保镖,并且以每天过1000万的速度增长。按照以前隐私保护器 的速度计算,如果三天之内开始放量就会感染8000万QQ用户”,另外马也公布了”QQ的用户中大约有60%装了360,所以至少一个亿以上的用户” ,“不采取措施QQ三天就可能全军覆没”,并爆出不少周鸿祎和腾讯之间的内幕。“刚开始要我们投资他,就像微软投资Facebook一样,高价买个小股, 后来还曾说要联合我们打百度,说把搜索流量卖给我们,他会出一个拦截百度的东西,先打他的医疗广告,打掉他30%的收入” 很快,周鸿祎在5日当晚连续接受搜狐和新浪专访,表态“马化腾臆断很多 绝对不会做IM”,但其实话里还有话,自己不做不等于不联合别人做。凌晨又亲自发表一封名为“不得不说的话”的公开信,追溯了腾讯和360之间的恩怨。信中周鸿祎表示腾讯此前抄袭360安全卫士并强制推广的行为,是欲置360于死地。这种“明目张胆地欺负人”,使得360选择“必须得反抗”。 周鸿祎的市场策略明显技高一筹,在新浪和搜狐接受专访,可以拉拢门户网站对他的亲和度,门户本来就是腾讯的死敌,显然马化腾不可能接受他们的专访,虽然腾讯在新浪微博开设了帐号。 周鸿祎这封信非常犀利,既检讨了过去,又显示了豪情, “我赚的钱,虽然不如别人那么多,但这一辈子即使啥事也不干,也够花了。但是,我心里就会问我自己:看着别人上当受骗,那样做有意思吗?2006 年,流氓软件满大街都是,杀毒软件厂商有技术能力,但谁都不去管,怕得罪人,又不赚钱。360做了,得罪了不少人,但用户很欢迎。” “做360,我就一定要做一个让用户觉得有用的东西,有价值的东西,一定要做别人不敢做的事。马化腾说扣扣保镖是超级病毒,能感染,但360敢做这种得罪用户的事吗?用户骂360的产品,我都不敢睡觉,非得了解透了,找了负责人解决一下才睡得着。” 再次想起国共重庆谈判时候,毛主席发表沁园春一词,全国知识分子为之倾倒,而蒋介石请其文胆写的回应词却四平八稳。 盘点目前战况结果: 从大众来看,360大大提升品牌影响力,虽然市场份额受影响(周表示360下降20%) QQ形象严重受损,大部分的公开信都呼吁腾讯停止目前垄断地位的行为。 从业界来看,大部分公司都是两家公司的对手,短期内是会从中得到双方失去的市场份额,看看百度指数里面其他浏览器的指数成倍上升。长期来看,360 的“免费+安全”的胡罗卜大棒手法,腾讯的“模仿+捆绑”的策略是所有业界公司创新的噩梦,如果能通过这次战争,约束行业竞争的手法,规范软件竞争的行 为,甚至促进关于软件互联网领域反垄断的管理条例,那就是行业进步的大好事。 双方后续较量还将继续,扣扣保镖是否病毒和外挂是关键问题,这个双方要动用自己的各种力量了。CSDN特约评论员将关注战事的进一步发展,做出相应的点评。 这一战会对业界的发展产生什么样的影响, 腾讯会因此而最后走向衰落吗?360能笑到最后成为新霸主吗?还是涌现出新帝国,无人能知,但只有能真正极大满足用户需要,成为用户入口平台的企业才能成就未来的新帝国。 未来10年将是IT技术巨大变革的黄金十年,通信业、互联网业、软件业、IT硬件行业、媒体内容产业之间的既有格局和藩篱被打破了,且让我们静观历史的演变吧。

客户端与服务器同步数据

需求: 1、服务器端程序是J2EE架构,运行在J2EE服务器上。数据库是Oracle. 2、客户端是Java应用程序,数据库使用的是SQLite; 3、客户端从服务器同步数据。 4、客户端与服务器上数据库中表结构基本相同。 5、客户端发出同步请求时,同步。 总体设计 流程: 1、客户发出同步请求,包含同步哪些数据的条件; 2、服务器响应请求:根据客户端发出的条件准备SQL语句; 3、 创建SimpleOracleJDBCReader实例,该实例可以根据一条SQL查询语句从数据库中获得对应的数据,以中间类型的数据结构存在;创建 SimpleXMLWriter实例,该实例可将中间类型数据写出到XML文档中。创建一个搬运器,将数据从Oracle数据库搬运到XML文件中。 4、服务器返回给客户端一个数据流.该数据流从第3步中生成的xml文件中取数据,发送到客户端 5、客户端接收从服务器发来的xml数据流,生成xml文件,保存在本地 6、在客户端创建SimpleXMLReader从下载的xml读出数据,以中间类型的形式存在;创建SimpleSQLiteJDBCWriter,将中间类型的数据写入到SQLite中;创建一个搬运器,将数据从XML搬运到SQLite数据库文件中。 服务器端程序 private IBaseDAO copyDAO; private String cachePath = "d:/test/"; /** * 组装更新数据 * * @date 2010-11-2 * @param os * @return */ public String getUpdateData(String xmlName, OutputStream os){ if(xmlName != null){ try { getXML(xmlName , os); } catch (Exception e) { e.printStackTrace(); } return null; } else { List<String> sqlList = getSql(); if(sqlList.size()==0){ return null; } String result = null; try { result = createXMLS(sqlList); os.write(result.getBytes()); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally{ if(os != null){ try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } return result; } } /** * 生成多个xml * * @date 2010-11-2 * @param sqlList * @return * @throws Exception */ private String createXMLS(List<String> sqlList) throws Exception{ StringBuffer sb = new StringBuffer(); String temp = null; for(String sql : sqlList){ temp = createXML(sql); if(temp != null){ sb.append(temp).append(","); } } return sb.toString(); } /** * 生成xml * * @date 2010-11-2 * @param sql * @return * @throws Exception */ private String createXML(String sql) throws Exception{ Reader reader = new SimpleJdbcReader(sql, copyDAO.getConnection()); String objectName = reader.getHeader().getObjectName(); String name = "data_"+objectName+"_"+System.currentTimeMillis()+".xml"; File xmlfile = new File(cachePath + name); if(!xmlfile.exists()){ xmlfile.createNewFile(); } Writer xmlWriter = new SimpleXmlWriter(reader.getHeader(), xmlfile); new SimpleTractor(reader, xmlWriter).start(); return objectName+":"+name; } /** * 下载一个xml文档 * * @date 2010-11-2 * @param xmlName * @param os * @return * @throws Exception */ public InputStream getXML(String xmlName, OutputStream os) throws Exception{ File file = new File(cachePath + xmlName); FileInputStream is = null; try { if(file.exists()){ is = new FileInputStream(file); byte[] buffer = new byte[8096]; int length = -1; while((length = is.read(buffer)) != -1){ os.write(buffer, 0, length); } } else { return null; } } catch (RuntimeException e) { e.printStackTrace(); } finally{ if(is != null){ try { is.close(); } catch (RuntimeException e) { e.printStackTrace(); } } if(os != null){ try { os.close(); } catch (RuntimeException e) { e.printStackTrace(); } } file.delete(); } return null; } /** * 组装sql * * @date 2010-11-2 * @return */ private List<String> getSql(){ List<String> sqlList = new ArrayList<String>(); sqlList.add("select * from users"); return sqlList; } 客户端程序 /** * 更新数据 * * @date 2010-11-2 * @param types * @param verison */ private void updateData(String[] types, String verison){ try { // 请求服务器准备xml格式的更新数据,每个表一个xml文档,返回xmlName格式是 // tableName1:xml文件名1,tableName2:xml文件名2,.... String[] xmlNames = getXMLNames(types, verison); if (xmlNames != null && xmlNames.length > 0) { String urlString = serverUrl + "?copyBean.xmlName="; File xmlFile = null; for (String xml : xmlNames) { if (xml == null) { continue; } // xml格式是 tableName1:xml文件名1 String[] temp = xml.split(":"); if (temp == null || temp.length < 2) { continue; } // 下载xml文件 xmlFile = getFileResponse(urlString + temp[1]); // 插入新数据 Reader reader = new SimpleXmlReader(xmlFile); Writer writer = new SimpleSQLiteJdbcWriter(copyDAO.getConnection(), reader.getHeader()); new SimpleTractor(reader, writer).start(); // 删除临时文件 xmlFile.delete(); } //更新版本号 updateVersion(verison); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (DocumentException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } /** * 请求服务器准备xml格式的更新数据,每个表一个xml文档,返回xmlName格式是 * * @date 2010-11-2 * @throws IOException */ private String[] getXMLNames(String[] types, String version) throws IOException { String typeStr = ""; for (String t : types) { typeStr += "&copyBean.allInfoTypes=" + t; } String orgId = SysContext.getCurrentUserFromSession().getGroup() .getId(); String urlString = serverUrl + "?copyBean.fromGroupId=" + orgId + typeStr; if (version != null) { urlString += "&copyBean.verison=" + version; } String result = getStringResponse(urlString); if (result != null) { String[] fileNames = result.split(","); return fileNames; } else { return null; } } /** * 获得字符串请求 * * @date 2010-11-2 * @param urlString * @return * @throws IOException */ private String getStringResponse(String urlString) throws IOException { InputStream is = sendHttpRequest(urlString); StringBuffer sb = new StringBuffer(); try { byte[] buffer = new byte[8096]; int length = -1; while ((length = is.read(buffer)) != -1) { sb.append(new String(buffer, 0, length)); } } catch (RuntimeException e) { e.printStackTrace(); } finally { try { is.close(); } catch (RuntimeException e) { } } return sb.toString(); } /** * 获取文件 * * @date 2010-11-2 * @param urlString * @return * @throws IOException */ private File getFileResponse(String urlString) throws IOException { InputStream is = sendHttpRequest(urlString); File xmlfile = new File("data_client_" + System.currentTimeMillis() + ".xml"); OutputStream os = null; if (!xmlfile.exists()) { xmlfile.createNewFile(); } os = new FileOutputStream(xmlfile); try { byte[] buffer = new byte[8096]; int length = -1; while ((length = is.read(buffer)) != -1) { os.write(buffer, 0, length); } } catch (RuntimeException e) { e.printStackTrace(); } finally { try { os.close(); } catch (RuntimeException e) { } try { is.close(); } catch (RuntimeException e) { } } return xmlfile; } /** * 发送请求 * * @date 2010-11-2 * @param urlString * @return * @throws IOException */ private InputStream sendHttpRequest(String urlString) throws IOException { HttpURLConnection httpConnection = null; URL url; int code = -1; for (int i = RETRY; i > 0; i--) { try { url = new URL(urlString.toString()); httpConnection = (HttpURLConnection) url.openConnection(); httpConnection.setRequestMethod("GET"); httpConnection.setDoOutput(true); httpConnection.setDoInput(true); httpConnection.setConnectTimeout(TIMEOUT); httpConnection.setReadTimeout(TIMEOUT); code = httpConnection.getResponseCode(); if (code != HttpURLConnection.HTTP_OK) { continue; } break; } catch (SocketTimeoutException e) { if (i == 1) { throw new RuntimeException(e); } else { continue; } } catch (UnknownHostException e) { if (i == 1) { throw new RuntimeException(e.getMessage()); } else { continue; } } catch (Exception e) { throw new RuntimeException(e); } } if (code == HttpURLConnection.HTTP_OK) { return httpConnection.getInputStream(); } else { return null; } }

DataCross:SimpleSelectFieldCacheWriter及用途

SimpleSelectFieldCacheWriter是DataCross中的一个写入器,主要是将选择指定的定段内容写入到指定的缓存中。 在使用DataCross进行数据格式转换的过程中,往往需要收集数据中的某些字段的信息,以便另做处理。如:从数据为中导出一个表的数据,其中有一个字 段是图片路径。如果要将数据从一个系统中导出到另一个系统时,就要收集这些图片的路径信息,以便将图片数据一起导到另一个系统中。 SimpleSelectFieldCacheWriter的构造方法如下: public SimpleSelectFieldCacheWriter(Header header, List collectFiled, List result);其中header是头信息,就是要写入对象的数据结构,collectField是指要收集header中的哪些字段信息,result 是指收集的内容存放在哪里。 使用方法如下: Reader reader = new SimpleExcelReader(src); List selectField = new ArrayList(); List result = new ArrayList(); Writer writer = new SimpleSelectFieldCacheWriter(reader.getHeader(), selectField, result); new SimpleTractor(reader, writer).start(); 详细见:http://datacross.daahe.com/