[转载]10年软件开发教会我最重要的10件事

mikel阅读(867)

[转载]10年软件开发教会我最重要的10件事(转) – 风舞清涟 – 博客园.

0. “面向对象”比你想象的要难得多

也许只有我有这种想法,不过我曾经以为计算机科学课上学过的“面向对象”是很简单的东西。我的意思是,创建一些类来模拟现实世界能有多难啊?其实,那还真是挺难的。

十年之后,我仍然在学习如何合理地建模。我后悔以前我没有花更多的时间来学习面向对象和设计模式。优秀的建模技术对于每一个开发团队都是非常有价值的。

1. 软件开发的难点在于沟通

这里的沟通是指与人的沟通,而不是socket编程。有时你的确会遇上棘手的技术问题,但是这种情况根本不常见。常见的问题在于那些你和项目经理之间的、你和客户之间的、还有你和其他开发者之间的误解。培养你的软技能吧。

2. 学会拒绝

当我刚开始工作的时候,我非常急切的想要去讨好别人。这也就是说,我几乎不能去回绝别人对我的要求。我加了很多班,但是还是不能完成他们交代给我的所有事情。结果他们表示不满意,而我也表示要崩溃了。

如果你从不回绝别人,你的答应就显得毫无意义。承担能力所及的事情,如果别人不停地指派给你更多的事情,你需要明确的表示那意味着将会耽误其他的工作。

为了应付这种事情,我会随身携带一张列有待办事项的纸(To-do list)。当人们叫我去做什么事情的时候,我就给他们看这张纸,并且问他们我应该为他们挤掉哪个事情。这是我用来拒绝别人的一种好办法。

3. 如果每件事都重要,那就什么事都不重要

我们这一行,总是强调每种特性都是同等重要的,其实并不是这样。敦促你的同事,让他们承担起工作。

如果你不强迫他们选择该做和不该做的事情,你会轻松很多。相反,让他们来为你选择你这周的任务。这会让你生产出来的东西变得最有价值。如果其他的部分都还是乱糟糟的,至少你已经完成了最重要的。

4. 不要过度考虑问题

我可以站在白板前面一整天策划事情,但是这并不意味着事情会向更好的方向发展,这仅意味着事情将变得更复杂。

我的意思并不是“你不应该去做任何策划”,只是如果我会在实现程序的时候会很快遇到我没考虑过的问题的话,那为什么我不去尝试把它做好呢?像戴夫·法洛所说的,“魔鬼居住于细节中,而驱走魔鬼的方法是实践,而不是理论”。

5. 去钻研一些东西,但不要钻牛角尖

克里斯和我花费了大量的时间钻研SQL服务器的深层部分。那真的很有趣,我也学到了很多知识,但是过了一段时间我意识到,知道了那么多的知识并不能帮助我解决业务上的问题。

举个例子:我知道在数据表层次,SQL服务器不会接受IU锁——它只会接受IX锁。这是一个性能调整,因为在大多数情况下,IU锁都会升级成IX锁。为了了解这些,我花掉了无数天做实验,我读了很多的书,还在会议上向微软的员工了解情况。然而我用过这个知识吗?没有。

6. 了解软件开发系统的其他方面

这对成为一个优秀的开发者是很重要的,但是若要在一个开发软件的系统中成为优秀的一员,你还需要去了解开发系统中剩下的部分在干什么。QA是如何工作的?项目经理在干什么?业务分析员在忙些什么?这些知识会让你与其他员工产生联系,并使你和他们之间的互动顺畅。

向你周围的人寻求帮助,以便学到更多的知识。有什么好书呢?大多数人都会为你的关注而高兴,并且很乐意帮助你。在这上花一点小时间会对你有很大的帮助。

7. 同事是你最好的老师

在我找到第一份工作的一年后,我们和另一所公司合并了。突然之间身边就多出很多聪明又经验丰富的人。我深刻的记得这是我感到多么自卑和愚蠢。我努力地学习,读了一本又一本的书,还是还是赶不上他们。我发现他们和我比起来有非常突出的优势。

现在,我不会因为和优秀的人一起工作而感到难受。我认为我有一生的时间去学习。我提出问题,并且非常努力地去了解我的同事们是怎么做出结论的。这也是为什么我加入了ThoughtWorks。把你的同事们看成财富,而不是竞争对手

关于学习,不论是哪个行业,都是永恒的话题,正如 Jonathan Danylko在总结自己20年的编程经验时所说到,“诚然,总有很多你不知道的技术,你可以从中学习以保持不落后。如果你有一种灵巧的方式来获取你需要的新技术,那你每天都应该坚持学习。”(编注:ThoughtWorks是一家全球知名的IT咨询公司。)

8. 做出可用的软件是最终目标

不管你的算法有多酷,不管你的数据库模式有多棒,不管你的什么什么有多么多么好,如果它不能搔到客户的痒处,它就不值一文。专注于做出有用的软件,同时准备继续做出后续软件,这才是正轨。

9. 有些人真的不可理喻

在你身边的大多数人总是很优秀的,你向他们学习,他们也向你学习。共同完成一件事情的感觉总是很好。然而不幸的是,你也有可能遇到例外。因为某些原 因,人可能会变得冷漠刻薄。萎靡不振的老板啊,满口谎言的同事啊,无知愚昧的顾客什么的。不要把他们看的太重。尽量避开他们,尽量把他们所带来的痛苦和影 响降到最小,但不要自责。只要你保持诚实并且尽力去工作,你就完成了你该做的事情。

[转载]程序员的职业规划书

mikel阅读(1007)

[转载]我的职业规划书 – 九妹 – 博客园.

下海做程序员的第一步也是最重要的一部,如何订制自己的程序之路。
很多人在一谈到自己的计划的时候,都会去看看别人是怎么做的,一味的跟随别人的规划,多少岁之前做coder,多少岁之前做manager.其实每个人都有自己的特点,你应该停下来好好的审视自己的职业,不要跟着别人的路去走了,你应该知道自己要何去何从.

我们的职业之路要怎么制定呢?毕竟程序员是一门职业,作为软件的开发人员,我们就是一个从事某一个职业的工人,公司雇佣我们,绝对不是因为公司爱我 们。虽然天天公司教导我们“公司我是家”但是深圳的住房公积金,公司的交的那部分,还是转嫁给我们自己承担。事实上,公司以前从没有爱过我吗,将来也绝对 不会。公司是你自己的那就另当别论了,否则,程序员就不是一个职业了,职业不就每天要我们去一个地方,呆上8个或者更多的小时,牺牲大量的脑细胞或者汗 水,然后领取报酬吗?职业就是生意,把我们做的生意说的惨淡点,就是出卖自己i的劳动力,换钱,再高级的白领也是如此。当然做生意有赚有亏得,想要在这个 行业里面成为佼佼者,那就是必须要知道自己应该如何去做这门生意,如何为自己创造利润?

如果把你的职业人生想象成为一个你正在开发的软件产品的生命周期,现在你的所有需求都已经明确(有车,有房,有钱,有公司等等),接下来我们就要开 始职业人生的设计了,在制定这个规划的时候,我们要重要的注意以下4个方面的内容,这个四个方面运用到整个人职业的生命周期中。

一、选择市场。 一定要谨慎的挑选你要关注的技术和商业领域。如何权衡风险和收益?
都是做软件开发,你究竟要做与硬件相关的还是与网络相关的?与手机相关的还是与汽车相关的?每一个分支都有专家和权威,你要确认自己想站在哪一个分支的顶点。在深圳很多程序员,为了生存,先入行再转行。程序员需要积累,面试官不喜欢一张白纸上满是编程理念的空头支票。

二、投资。

做生意哪有不投资就赚钱的好事,你的知识和技术就是你这件生意的基础。所以你要在这两个方面合理的投资,时间,金钱。只知道在理论上使用VB或者Java已经远远不够了,那么在新的环境下,新的平台下,又有哪些新的技术你应该具备的呢?

三、执行力。

用我老板的话来说单纯有技术出色的员工,并不能给公司带来利益。员工必须要有产出才行。有的时候一名优秀的员工产出远远不及一名普通的员工,反而有 时候会让简单的事情变的一团糟糕,2分钟一个简单的算法,被花上2天时间提高0.001%的效率这种事情也是经常发生的。所以我们应该考虑的是能否创造最 有利的价值而不是完美,

四、团队 。

程序员孤军奋战成不了大事。一个再优秀的程序员也完成不了整个windows操作系统的工作,虽然我见过一个人是可以独立完成破解windows的工作的。所以如果不想过于孤单和山寨,请找到一支正规军加入他们。

五、又是市场。

你们肯定会说,你开始写循环了是吧?怎么又是市场?
一个人选对了市场,投资技术,有了回报,有了产出,有了自己的团队,恭喜你,你离出产品 的日子不远了。但是你有没有考虑一下你的产品的市场,若是无人知晓,毫无用途,又怎么会有利润呢?你的成绩又怎么会被老板和同行认可呢?请记住:一个团队 奋斗了1个月写出来一个:Hello world!是赚不了钱的。

[转载]Asp.net mvc 网站之速度优化 -- 页面缓存

mikel阅读(1068)

[转载]Asp.net mvc 网站之速度优化 — 页面缓存 – enjoyeclipse – 博客园.

网站速度优化的一般方法

由于网站最重要的用户体验就是速度,特别是对于电子商务网站而言。

一般网站速度优化会涉及到几个方面:

1. 数据库优化 — 查询字段简历索引,使用数据库连接池和持久化,现在还有种趋势,就是选择使用No SQL作为补充;

2. 数据缓存 — 使用Memcached等;

3. 负载均衡 — 使用ngnix等

4. 页面缓存 — 将.aspx, .jsp等动态页面缓存或静态化为.html页面

5. 前端优化 — Yahoo 14条前端优化原则。

城江湖(Incity.me)针对 2 数据缓存, 4 页面静态化, 5 Yahoo 14条优化原则做了具体的实践,并获得了实际效果,以后的系列文章会举出一些实践方法和列出部分代码,这次主要针对页面缓存进行说明。

哪些地方需要页面缓存?

以InCity为例,首页商品分类帮助中心等都是用于展示商品和网站信息的,与用户的交互相对较少。在某个时间段内(1小时),所有用户看到的页面都应该是相同的, 并不会因为不同的用户而显示不同的信息。

全局页面缓存 OutputCache

InCity是基于ASP.NET MVC开发的,熟悉ASP.NET MVC的童鞋都知道,ASP.NET MVC自带了一个属性叫OutputCache,  最常用的是Duration和VaryByParam两个参数:

MSDN:

Duration:表示页或用户控件进行缓存的时间(以秒计)

VaryByParam:分号分隔的字符串列表,用于使输出缓存发生变化。

Code:

[OutputCache(Duration=”3600″ VaryByParam=”type”)]

public ActionResult Catalog(string type)

解释一下:

1. 用户第一次输入http://incity.me/catalog/food,从后台获取,并为catalog/food生成缓存页面,3600秒内缓存页面有效。

2. 用户再次输入http://incity.me/catalog/food,从缓存页面获取。

3. 当用户第一次输入http://incity.me/catalog/play的时候,因为{type}从food变成了play,数据从后台获取,并为catalog/play生成缓存代码3600秒内有效。

4.用户再次输入http://incity.me/catalog/play,从缓存页面获取。

局部页面缓存 PartOutputCache

上 述的解决方法对于大部分都可以处理,但是如果遇到下面的情况怎么办?登录前首页右侧的面板是显示登录区,登录后是显示用户信息,而首页如果采用 OutputCache全局页面缓存的话,则右侧显示不同的账户信息的。因为前面我们已经提到,在某个时间段内(1小时),所有用户看到的页面都应该是相 同的。

登录前:

登录后:

这时候就需要针对左侧的商品作局部缓存,而对右侧不使用缓存。如何达到这个效果呢?遗憾的是,这时候微软官方的ASP.NET MVC并未提供这种功能,因此参考使用了PartOutputCache,用法如下:

[PartOutputCache(CacheDuration = 3600)]

public ActionResult ShowCase()

aspx页面代码则变成了

<div id=”Container”>

<!–使用了缓存–>

<%Html.RenderAction<HomeController>(p => p.IndexShowCase());%>

<!–没有使用缓存–>

<%Html.RenderAction<HomeController>(p => p.LoginPanel());%>

</div>

转载自: dev.incity.me

PartOutputCache源代码看这里

[转载]最专业的通用.NET插件平台——尤埃开放服务平台介绍

mikel阅读(926)

[转载]最专业的通用.NET插件平台——尤埃开放服务平台介绍 – 道法自然 – 博客园.

尤埃开放服务平台(UIOSP)是基于.NET设计的插件化平台。该平台设计的初衷是: (1)为所有.NET应用环境设计一个通用的插件平台,即该平台能够以标准化的插件规范来开发基于.NET Framework的控制台应用、WinForm应用、ASP.NET应用、WPF应用、Windows服务应用及SilverLight应用和基 于.NET Compact Framework的移动应用设计;(2)为基于.NET的统一开放平台提供支持,即开发人员基于该平台设计的可完全复用的插件可以通过统一开放平台开放 给用户,这样开发者或者最终用户可以从该平台获取需要的模块然后组装成最终软件;(3)为企业构建一个基于插件库的标准化的软件生产线,用于支持软件产品 自动升级、远程部署、远程管理、统一版本、局部更新、知识积累。

UIOSP插件平台通过对.NET CLR进行扩展实现优雅的通用的插件化框架,它支持模块化与插件化、面向服务架构、模块扩展三大功能。模块化与插件化为.NET应用程序提供了物理隔离的 模块支持,它为每一个物理隔离的模块提供了标准的规范、隔离的目录结构、隔离的类加载器、多版本并存支持、插件依赖支持等功能;面向服务架构是实现模块化 通讯的手段,每一个模块通过服务总线来注册/查询绑定/卸载服务,服务是模块间交互的手段。在该平台,服务是可管理的,这意味着插件间的交互可以被管理和 监控。模块扩展功能为插件提供了可扩展机制,这样我们可以在不改变原有模块的代码情况下,来注入新的功能或更新原有功能。

你可以从插件平台这 个链接下载到该平台的安装包,一旦安装后,它将为你提供:(1)用户开发指南;(2)Visual Studio标准项目模板,可用于创建不同应用环境的主程序和插件;(3)基于Visual Studio的插件配置工具,用于插件可视化配置;(4)远程控制台,可用于查看插件内核的插件状况,动态安装/启动/停止/卸载插件。

image

下 图是基于该插件平台的软件系统的通用架构。在这里你根据应用系统的环境,创建相应的主程序,并利用UIOSP的BundleRuntime类来启动插件框 架。在UIOSP,插件用英语单词Bundle来表示,Bundle可以翻译为插件或者模块,而BundleRuntime就是插件运行时了,这与WWF 的WorkflowRuntime概念类似。一旦插件框架被启动,它将会加载位于plugins目录下的所有标准化的插件,并将插件组装成一个应用系统。 应用程序的开发可以按2个步骤走:(1)创建主程序;(2)创建插件。

image

下图则是基于插件库的企业级应用系统架构。在这里,企业将建立自己的私有插件/模块仓库,构建自己的产品生产线,使用一致的方式来构建、维护、部署、升级、管理软件产品。

image

接下来以一个Demo来演示一下如何来演示这个插件框架的使用方法。

首先运行Visual Studio,然后使用向导创建一个“UIOSP”=>“高级Windows窗体应用程序”项目。

image

这样你就使用UIOSP提供的项目模板创建了一个默认的WinForm插件主程序了。

image

你 可以发现创建的主程序包括:Program.cs启动类、bin/plugins目录及该目录下的三个默认插件。Program.cs类在这里完成的工作 很简单:(1)创建一个BundleRuntime并调用Start方法来启动插件内核;(2)从插件内核服务总线中获取一个类型为Form的服务,即主 窗体,然后运行该主窗体。一旦程序启动,那么在bin/plugins目录下的插件会被BundleRuntime加载并启动。这个项目里面有一个 WinFormShellPlugin插件,该插件是一个通用的WinForm主窗体,该主窗体实现了菜单、导航栏、内容区域、状态栏,并支持换肤。你可 以试一下启动这个程序,结果如下。

image

这 个主程序包含的WinFormShellPlugin插件已经为你提供了一个漂亮的防Office的Windows空的壳子。下面我们来试着开发一个应用 插件。回到Visual Studio,选中解决方案然后点击“添加新建项目”,选中“UIOSP”=>“高级Windows窗体插件”,命名为AppPlugin。需要注 意的是,这个AppPlugin插件项目必须位于bin/plugins目录下。

image

浏览一下这个AppPlugin插件项目,其内容如下。插件包含一个Activator.cs、Manifest.xml、一个窗体、一个用户控件和一个资源。

image

在 插件中,Manifest.xml是插件的配置文件,它用于声明插件的标识、名称、启动顺序、初始启动状态、本地类库、依赖的插件和类库、扩展信息。双击 插件,你可以使用基于Visual Studio的插件配置工具来查看和更改配置信息。如下图所示。它包含四个标签页:(1)基本:用于配置插件的基本信息;(2)运行时:用于配置插件需要 的类库、依赖的插件或依赖的插件的类库信息;(3)服务:用于配置插件提供的服务;(4)扩展:用于定义插件的扩展点和对其它插件的扩展信息。

image

按 F7可以查看Manifest.xml的源代码,如下所示。<Bundle>节点定义基本信息,<Activator>节点定义 指定插件执行入口和出口的类型,其定义就是这个项目的AppPlugin.Activator类型,<Runtime>指定了这个插件的本地 类库,<Extension>节点定义了对WinFormShellPlugin的扩展,它向这个插件的左边的导航栏注册了2个菜单和菜单点 击时显示的窗体/用户控件的类型。

1 <?xml version=”1.0″ encoding=”utf-8″ ?>
2 <Bundle xmlns=”urn:uiosp-bundle-manifest-2.0″ SymbolicName=”AppPlugin” Name=”AppPlugin” Version=”1.0.0.0″ InitializedState=”Active”>
3 <Activator Type=”AppPlugin.Activator”/>
4 <Runtime>
5 <Assembly Path=”bin\AppPlugin.dll”/>
6 </Runtime>
7 <Extension Point=”UIShell.Applications”>
8 <Application Title=”AppPlugin” ToolTip=”AppPlugin” Icon=”AppPlugin.Resources.shell.png”>
9 <Menu Text=”UserControl1″ ToolTip=”UserControl1″ Icon=”AppPlugin.Resources.shell.png” Class=”AppPlugin.UserControl1″/>
10 <Menu Text=”Form1″ ToolTip=”Form1″ Icon=”AppPlugin.Resources.shell.png” Class=”AppPlugin.Form1″/>
11 </Application>
12 </Extension>
13 </Bundle>

这 个插件的Activator.cs文件定义了插件的入口和出口。当插件被启动时,这个类的Start方法会被调用并传入一个插件上下文参数 (IBundleContext);反之,如果插件被停止,Stop方法被调用。IBundleContext这个对象是插件与内核交互的唯一参数,你可 以通过它来注册/查询/绑定/卸载服务;可以通过它来或者这个插件对应的Bundle对象;可以通过它来查询插件内核的插件情况,动态安装/启动/停止 /卸载插件;可以监听插件内核的各种事件。接下来,你可以试着运行一下这个应用程序了。

image

你 可以看到,构建的插件向WinFormShellPlugin的导航栏注册了由“UserControl1”和“Form1”两个菜单项组成的 “AppPlugin”菜单组,一旦点击“UserControl1”菜单,这个用户控件就显示在右边的内容区域。随着你构建越来越多的插件,他们将向界 面中注册越来越多的菜单和窗体,那一个基于插件平台的具有漂亮界面的WinForm应用程序构建完成了。不过,还没完,下面你还可以试着使用远程管理控制 台工具来管理插件内核。为了更好演示动态性,我又创建了一个DemoPlugin插件。

在这里,你可以使用install/list/start/stop/uninstall指令来操作。首先,输入list来查看插件内核加载的情况。如下所示,它列出了5个插件,当然有一个没有显示,就是ID为1的系统插件。

image

接下来你可以使用stop 2/start 2/uninstall 2来停止AppPlugin/启动AppPlugin/卸载AppPlugin。下面看一下Stop 2指令即停止AppPlugin的效果。

image

你 可以发现AppPlugin这个插件已经被停止,它创建的菜单也从界面上消失。这就是UIOSP的另一重要特性:动态性!你可以通过远程控制指令来更改软 件的行为。有关UIOSP这个最专业的插件平台的介绍,先到这,后面我将介绍UIOSP构建的一个实际的案例——SaaS应用商店开放平台,它使用的是基 于插件仓库来构建的开放平台。

有任何问题欢迎加入UIOSP交流群进行讨论,群号:121369588。

转载Android中包含多个Activity的应用退出按钮实现

mikel阅读(1136)

转载Android中包含多个Activity的应用退出按钮实现 – deaboway – 博客园.

Android编程中,application这样的名词似乎变得那样的不常见,而让大家更为熟悉的是activity、intent、 provider、broadcast和service。但其实Android中的application也有着它自身的用处。打开manifest文 件,会看到有一个application配置标签,这就是有关application的使用了。

就是说application是用来保存全局变量的,并且是在package创建的时候就跟着存在了。所以当我们需要创建全局变量的时候,不需要再像j2se那样需要创建public权限的static变量,而直接在application中去实现。只需要调用Context的getApplicationContext 或者Activity的getApplication 方法来获得一个application对象,再做出相应的处理。

退出按钮实现

首先,创建Application来存储所有打开的Activity的list。代码如下:

package com.deaboway.view;  
import java.util.ArrayList;  
import java.util.List;  
import android.app.Activity;  
import android.app.Application;  
public class Deaboway extends Application {  
    private List<Activity> mainActivity = new ArrayList<Activity>();  
    public List<Activity> MainActivity() {  
        return mainActivity;  
    }  
    public void addActivity(Activity act) {  
        mainActivity.add(act);  
    }  
    public void finishAll() {  
        for (Activity act : mainActivity) {  
            if (!act.isFinishing()) {  
                act.finish();  
            }  
        }  
        mainActivity = null;  
    }  
} 

其次,在所有Activity的 @Override public void onCreate(Bundle savedInstanceState) {}方法中加上:

      public void onCreate(Bundle savedInstanceState) {  
          super.onCreate(savedInstanceState);  
    Deaboway appState = (Deaboway)this.getApplication();  
    appState.addActivity(this);  
          setContentView(R.layout.main);  
         。。。。。。。  
      }  

第三,在退出按钮的地方调用:

   OnClickListener() {  
                public void onClick(View v) {  
                    Deaboway appState = (Deaboway)getApplicationContext();  
                    appState.finishAll();  
                }  
            }  

最后,要记得在manifest中的application标签中添加 android:name=”.Deaboway”

[转载]Android上OpenGL开发一些经验记录(上)

mikel阅读(1114)

[转载]Android上OpenGL开发一些经验记录(上) – YYX – 博客园.

Android沿用了J2ME的OPENGL ES API.

相比C版本的OpenGL,Opengl ES 没有glu和glut库,而且只能画三角形(多边形需要三角化)。

没有直接的drawXXX 方法,只有通过 glVertiexPointer传入顶点画图。

另外参数上,没有指针和C风格的数组,Java需要用Buffer类来代替这个。

先看Android的glVertexPointer :

GL10.glVertexPointer(int size, int type, int stride, Buffer pointer):

这个方法为 后面openGL绘图准备顶点数据。

size : 代表每个顶点包含几个坐标参数 ,如pointer的buffer中只含有 x,y坐标, 则传2, OpenGL会默认使用0作为z坐标。如果包含 x,y,z 坐标,则传3。其他值在这里都不适用。
type : 是一个枚举值,可以为 GL_FLOAT和 GL_FIXED,浮点数可对应java 的 float,要求pointer为 FloatBuffer.
GL_FIXED意为定点数,长度4字节,高16位表示整数部分,低16位表示小数部分。传入int值前需要先左移16位(即需扩大 0x10000倍)。要求pointer为IntBuffer.
stride :指每个元素之间,间隔多少个值。加入buffer中坐标点数值间紧密相连,那么stride就是0,如果点1,点2间还有不用到的值,则stride就是这种值的个数。
pointer:这是最需要注意的一个参数,也是Java版OpenGL特有的。Buffer类型是一个基类,具体的类型是 FloatBuffer还是IntBuffer要根据前面type参数来决定。
Java中的 Buffer分两种,一种direct,一种非direct.这里只支持 DirectBuffer,也就是通过ByteBuffer.allocateDirect(int cap) 分配而来的buffer.
通过allocateDirect 得到的是一个 ByteBuffer,实际使用时,如果要作为FloatBuffer,可以通过 ByteBuffer.asFloatBuffer来得到,IntBuffer也同样。
做到这些当然还不够,ByteOrder也对这个参数有影响。当的ByteBuffer作为FloatBuffer,则float的4字节默认是按照小端排列在directBuffer中,在
某些大端的设备中这个buffer的格式就不正确,需要根据设备设置ByteOrder.
所以以FloatBuffer为例,创建方法如下:
FloatBuffer buffer = ByteBuffer.allocateDirect(1024).order(ByteOrder.nativeOrder()).asFloatBuffer();
有了FloatBuffer,我们还需要将实际顶点坐标传入这个buffer。这只需要调用 FloatBuffer.put(float)的方法即可。
注意放顶点坐标是x,y…的格式,还是x,y,z…的格式要和前面第一个参数 size是2还是3统一。
所有的值放完以后,需要调用 buffer.rewind()或者 buffer.position(0),将buffer内游标置回0,否则OpenGL会从最后一次put的下一个位置开始读取。
关于三角化的算法:
Android的OpenGL API 画多边形目前只支持 triangle_fan,triangles, triangle_strip 三种。如果只有简单无洞的凸多边形,只需要将所有点当作triangle_fan的顶点就可以画出。
如果存在凹多边形,就需要进行三角化(当然凸多边形也可以三角化,保持逻辑上的统一)。
有个最简单的三角化算法叫做 ear clipping三角化。几何上非常容易理解:
一个多边形的一个顶点,和它相邻两个顶点可以组成一个三角形,如果这个三角形内部不存在这个多边形的其他顶点,就可以把这个顶点和相邻点组成的三角形当作一个ear.
这个ear可以被切下来(沿两个相邻顶点切)。每切一次,得到一个三角形和一个少了一个顶点的多边形,然后再对这个多边形做同样操作,直到剩下的这个多边形也只剩下3个顶点。
如此一来,这个多边形被完全分解为3角形。
要把把几何上的操作变成代码,只要解决这几个问题:
#如何判断多边形的一串顶点是逆时针还是顺时针排列的?
– 从某个顶点指向它下一个顶点,可以得到一个向量,多边形有几条边就得到几个向量,如果所有相邻两个向量的叉积(前一个向量和后一个向量的叉积)之和大于0,则排列是逆时针的,反之是顺时针的
(根据右手坐标系判断,一系列逆时针向量围成的面积是指向z轴正向的),为0有两种情况,这串点是直线,或者多边形某两条边交叉,这种多变形不符合这个三角化算法的条件。
#根据顶点顺逆情况,调整顶点排列,保证逆时针排序,则可以得到如下结论:
– 如果相邻两个向量,前一个向量和后一个向量叉积,值为正,则两个向量连接点这个顶点是凸点,值为负则为凹点。
– 如果有相邻3个顶点 p1,p2,p3 组成三角形,有另外一个顶点 P,如何判断P是否在三角形内?
分别做如下几个叉积p2P X p1p2, p3P X p2p3 , p1P X p3p1 ,如果这3个叉积同为正或同为负,则这个顶点在三角形内部。
关于 glEnableClientState, glDisableClientState,
glEnableClientState(int cap);
cap : GL_COLOR_ARRAY
GL_EDGE_FLAG_ARRAY
GL_FOG_COORD_ARRAY
GL_INDEX_ARRAY
GL_NORMAL_ARRAY
GL_SECONDARY_COLOR_ARRAY
GL_TEXTURE_COORD_ARRAY
GL_VERTEX_ARRAY
是用来启用或者关闭和这些数组功能。
如同前面的glVertexPointer ,还有别的诸如 glColorPointer, glEdgeFlagPointer等等接口,
glVertexPointer描述顶点位置,其他的描述顶点或者平面的属性。
这些数组默认都是disable状态,如果用这两个接口enable了某个数组,那么当glDrawArrays 调用之前必须把相应的数组准备好。否则draw不能成功。
所以如果不准备传入某个数组,draw之前要先 disable这个数组(如果前面enable过)。
反之如果要使用某个数组,也要事先enable。

还有Java中缺少的API,比如没有glPerspective的时候如何用glFrustm实现glPerspective,以及没有gluLookAt的时候如何用modelView来得到同样效果。将在之后文章里面解说。

[转载]关于商城系统中商品类别的设计

mikel阅读(873)

[转载]关于商城系统中商品类别的设计 – 七七可可 – 博客园.

以XiZiShop为例,如下效果图:

上图红色方框所示为一级类别。

上图所示为二级类别、三级类别和筛选条件类别,以及筛选条件的值。

数据库设计步骤如下:

【步骤一】对于一级类别、二级类别,三级类别,我统一把它们放在一张表里面,名曰:栏目表(T_Columns),各级的父子关系通过表中的FatherCol这一列去进行关联。如下图:

【步骤二】建立好存储一级类别、二级类别和三级类别的表之后,再开始考虑“筛选条件表”(表名称:T_FilterCategory)和“筛选条件值表”(表名称:T_FilterAttributes) 的设计。

然后再分析“筛选条件表”和“筛选条件值表”之间的对应关系。

同一个筛选条件可以有多个筛选条件值。例如:对于手机“品牌”来说,它下面可以有多个筛选条件值:三星、摩托罗拉、苹果…..

同一个筛选条件值又可以被多个筛选条件所拥有。

观察上图中的红色方框内容,我发现手机“品牌”里有“三星”,笔记本“品牌”里也有“三星”,换句话说,“三星”既属于手机“品牌”又属于电脑“品牌”,这样一来,“三星”就可以对应多个“品牌”了,因此得出结论同一个筛选条件值有可能被多个筛选条件所拥有。

综合上述1和2,我得出“筛选条件表”和“筛选条件值表”之间是多对多的关系。于是,按照数据库设计规范,需要为这两张表添加一个中间表,名曰:(RF_FilterCategory_TFilterAttributes)

然后建立它们的外键关联:

然后再分析“筛选条件表”和“栏目表”之间的对应关系:

“栏目表”属于“筛选条件表”的父表,即只有“栏目表”中的三级类别才和“筛选条件表”直接关联,如下图:

分析它们的关系:

1:一个三级类别可以有多个筛选条件。

2:同一个筛选条件可以被多个三级类别拥有。如下图:

如上图:“品牌”和“价格”可以同时被三级类别中的“手机”和“对讲机”拥有。所以,“栏目表”和“筛选条件表”之间也是多对多的关系。于是又需要建一个 中间表,名曰:(RF_Columns_FilterCategory),如下图:

然后建立外键关系如下图:

设计完这一步,整个关系图如下:

到了这一步,似乎数据库已经设计的很完美了,但是它有一处致命的硬伤!

这个硬伤在哪儿呢,答案见续篇。

[转载]开源中最好的Web开发的资源

mikel阅读(1414)

[转载]开源中最好的Web开发的资源 | 酷壳 – CoolShell.cn.

学习HTML 5编程和设计

服务器端的软件

  • ★ Node.js 是服务器端的 JavaScript 环境,其使用了异步事件驱动模式。其让Node.js在很多互联网应用体系结构下获得非常不错的性能。 源码 和 实时演示
  • PhantomJS 也是一个服务器端的 JavaScript API的WebKit。其支持各种Web标准: DOM 处理, CSS 选择器, JSON, Canvas, 和 SVG
  • Lighttpd 一个轻量级的开源Web服务器。新闻,文档,benchmarks, bugs, 和 download. Lighttpd 支撑了几个非常著名的 Web 2.0 网站,如:YouTube, wikipedia 和 meebo.
  • NGinx, 性能巨高无比的轻量级的Web服务器。比Apache高多了。花了6年的时间,终于走到了1.0版。
  • Apache HTTP Server 是一个很流行的并支持多个流行的操作系统的Web服务器。
  • ★ PHP 可能是最流行的服务器端的Web脚本动态处理语言。
  • 当然,还有 RubyPythonErlangPerlJava.NETAndroidC++Go, Fantom,CoffeeScriptD, …

PHP 框架和工具

  • ★ WordPress 是一个基于博客系统的开源软件。参看《WordPress是怎么赢的?
  • Drupal 是一个内容管理系统 (CMS).
  • Centurion 是一个新出现的开源 CMS ,一个灵然的 PHP5 Content Management Framework. 使用 Zend Framework, 其组件坚持通用,简单,清楚和可重用的设计原则。
  • phpBB 一个开源的论坛(国内的Discuz!更多)
  • ★ SimplePie : 超快的,易用的,  RSS  和 Atom feed PHP解析。
  • ★ PHPthumb, PHP 图片处理库
  • ★ PHPMailer 强大的全功能的PHP邮件库
  • PubSubHubbub协议,一个简单,开放, server-to-server 的 pubsub (publish/subscribe) 协议——Atom and RSS的扩展。
  • 更多的请参看 – 20个你应该知道PHP库 和 9个强大免费的PHP库

数据库

  • ★ Apache CouchDB 是一个面向文档的数据库管理系统。它提供以JSON 作为数据格式的REST 接口来对其进行操作,并可以通过视图来操纵文档的组织和呈现。.源码.
  • MonoQL 是一个采用PHP+ExtJS开发的MySQL数据库管理工具。界面极像一个桌面应用程序,支持大部分常用的功能包括:表格设计,数据浏览/编辑,数据导入/导出和高级查询等。
  • MariaDBMySQL的一个分支,由MySQL 创始人Monty Widenius 所开发。GPL,用来对抗Oracle所有的MySQL的license的不测。自Oracle收购SUN以来,整个社区对于MySQL前途的担忧就没有停止过。
  • ★ SQLite 不像常见的客户端/服务器结构范例,SQLite引擎不是个程序与之通信的独立进程,而是连接到程序中成为它的一个主要部分。所以主要的通信协议是在编程 语言内的直接API调用。这在消耗总量、延迟时间和整体简单性上有积极的作用。整个数据库(定义、表、索引和数据本身)都在宿主主机上存储在一个单一的文 件中。它的简单的设计是通过在开始一个事务的时候锁定整个数据文件而完成的。库实现了多数的SQL-92标准,包括事务,就是代表原子性、一致性、隔离性 和持久性的(ACID),触发器和多数的复杂查询。不进行类型检查。你可以把字符串插入到整数列中。某些用户发现这是使数据库更加有用的创新,特别是与无 类型的脚本语言一起使用的时候。其他用户认为这是主要的缺点。
  • SQL 在线设计编辑器,这一节的那个图片就是这个在线编辑器的样子了。一个画数据库图表的在线工具。很强大。

API 和 在线数据

在线代码和媒体编辑器

  • ★ CodeRun Studio一个基于JavaScript语言开发的跨平台的集成开发环境,它立足于云计算的设计思路,方便开发者在浏览器端便可以轻松开发、调试和部署网络应用程序。(参看《Coderun.com 在线开发IDE》)
  • Cloud9 IDE – 一个基于Node.JS构建的JavaScript程序开发Web IDE。它拥有一个非常快的文本编辑器支持为JS, HTML, CSS和这几种的混合代码进行着色显示。
  • ★ jsFiddle – Javascript的在线运行展示框架,这个工具可以有效的帮助web前端开发人员来有效分享和演示前端效果,其简单而强大 (JavaScript, MooTools, jQuery, Prototype, YUI, Glow and Dojo, HTML, CSS)
  • Akshell一种云服务,它使用服务端的JavaScript和在线的IDE帮助开发者进行快速应用程序开发。 它还提供云托管,所以部署是即时的。
  • JSONeditor, 一个好用的JSON 编辑器
  • ★ TinyMCE 一个轻量级的基于浏览器的所见即所得编辑器,支持目前流行的各种浏览器,由JavaScript写成。
  • Ext Designer 是一个桌面应用工具,帮助你快速开发基于ExtJS 的用户界面。
  • ★  LucidChart,一款基于最新的html5技术的在线图表绘制软件,功能强大,速度快捷,运行此软件需要支持html5的浏览器。
  • Balsamiq Mockups, 产品设计师绘制线框图或产品原型界面的利器。
  • Color Scheme Designer 3 – 一个免费的线上调色工具
  • ★ Pixlr, 是一个来自瑞典基于Flash的免费在线图片处理网站。除了操作介面和功能接近Photoshop,还是多语言版本,支持简体中文。(以前酷壳介绍过
  • Aviary, 是一个基于HTML5 的在线图片处理工具,可以很容易的对图片进行后期处理。 Aviary API
  • Favicon Generator, 线上favicon(16×16)制作工具。

代码资源和版本控制

  • ★ GitHub 是一个用于使用Git版本控制系统的项目的基于互联网的存取服务。
  • Git 是一个由Linus为了更好地管理linux内核开发而创立的分布式版本控制/软件配置管理软件。其巨快无比,高效,采用了分布式版本库的方式,不必服务器端软件支持,使源代码的发布和交流极其方便。
  • Google Code 谷歌公司官方的开发者网站,包含各种开发技术的API、开发工具、以及开发技术参考资料。
  • Google Libraries API Google 将优秀的 JavaScript 框架部署在其 CDN 上,在我们的网站上使用 Google Libraries API 可以加速 JavaScript 框架的加载速度。
  • Snipplr 一个开放的源代码技巧分享社区,号称Code 2.0。和一般的源码分享网站不同,它针对的并不是大型网站源码,而是一些编程的代码技巧。

JavaScript 桌面应用框架

  • ★ jQuery 是一个快速、简单的JavaScript library, 它简化了HTML 文件的traversing,事件处理、动画、Ajax 互动,从而方便了网页制作的快速发展。  源码APIAPI浏览很不错的文档.
  • ★ 官方的 jQuery User Interface (UI) library (演示和文档). 源码,Themes RollerDownload.
  • YUI 2 — Yahoo! User Interface Library
  • Mootools, 一个超级轻量级的 web2.0 JavaScript framework
  • Prototype 提供面向对象的Javascript和AJAX
  • Dojo The Dojo Toolkit,一个强大的无法被打败的面向对象JavaScript框架。主要由三大模块组成:Core、Dijit、DojoX。Core提供 Ajax,events,packaging,CSS-based querying,animations,JSON等相关操作API。Dijit是一个可更换皮肤,基于模板的WEB UI控件库。DojoX包括一些创新/新颖的代码和控件:DateGrid,charts,离线应用,跨浏览器矢量绘图等。
  • ★ Ext JS 4, 业内最强大的 JavaScript framework。
  • PHP.js, 一个开源的JavaScript 库,它尝试在JavaScript 中实现PHP 函数。在你的项目中导入PHP.JS 库,可以在静态页面使用你喜欢的PHP 函数。

JavaScript 移动和触摸框架

  • ★ jQuery Mobile : 是 jQuery 在手机上和平板设备上的版本。jQuery Mobile 不仅会给主流移动平台带来jQuery核心库,而且会发布一个完整统一的jQuery移动UI框架。支持全球主流的移动平台。jQuery Mobile开发团队说:能开发这个项目,我们非常兴奋。移动Web太需要一个跨浏览器的框架,让开发人员开发出真正的移动Web网站。我们将尽全力去满 足这样的需求。 Sources.
  • Zepto.js Zepto.js 是支持移动WebKit浏览器的JavaScript框架,具有与jQuery兼容的语法。2-5k的库,通过不错的API处理绝大多数的基本工作。 Sources.
  • MicroJS : Microjs网站应用列出了很多轻量的Javascript类库和框架,它们都很小,大部分小于5kb。这样你不需要因为只需要一个功能就要加载一个JS的框架。
  • ★ PhoneGap :是一款开源的手机应用开发平台,它仅仅只用HTML和JavaScript语言就可以制作出能在多个移动设备上运行的应用。 Sources.
  • ★ Sencha Touch Sencha Touch 是一个支持多种智能手机平台(iPhone, Android, 和BlackBerry)的 HTML5 框架。Sencha Touch可以让你的Web App看起来像Native App。美丽的用户界面组件和丰富的数据管理,全部基于最新的HTML5和CSS3的 WEB标准,全面兼容Android和Apple iOS设备。
  • JQtouch, 是一个jQuery 的插件,主要用于手机上的Webkit 浏览器上实现一些包括动画、列表导航、默认应用样式等各种常见UI效果的JavaScript 库。 Sources.
  • DHTMLX Touch 针对移动和触摸设备的JavaScript 框架。DHTMLX Touch基于HTML5,创建移动web应用。它不只是一组UI 小工具,而是一个完整的框架,可以针对移动和触摸设备创建跨平台的web应用。它兼容主流的web浏览器,用DHTMLX Touch创建的应用,可以在iPad、iPhone、Android智能手机等上面运行流畅。

jQuery 插件

  • Waypoints 是一个jQuery 用来实现捕获各种滚动事件的插件,例如实现无翻页的内容浏览,或者固定某个元素不让滚动等等。支持主流浏览器版本。
  • Lazy loader 插件可以实现图片的延迟加载,当网页比较长的时候,会先只加载用户视窗内的图片,视窗外的图片会等到你拖动滚动条至后面才加载,这样有效的避免了因图片过多而加载慢的弊端。
  • TweenJS : 一个简单和强大的 tweening / animation 的Javascript库。
  • Easings 类Css3的jQuery 动画插件
  • Spritely 这个插件可以创建出如flash一样的动画效果,比如:在页面上有一只飞动的小鸟,一个动态滚动的背景等。
  • File Upload, jQuery 文件上传插件4.4.1
  • Slideshow/Carousel 插件. Sources.
  • Supersized – 全屏式的背景/幻灯片插件
  • Masonry i一款非常酷的自动排版插件,这款jQuery工具可以根据网格来自动排列水平和垂直元素,超越原来的css. Sources.
  • jQuery 简单 Layout 演示,管理各种边栏式,可改变大小式的布局。
  • Flexigrid – jQuery 数据表插件
  • Isotope绝对是一个令人难以置信的jQuery插件,你可以用它来创建动态和智能布局。你可以隐藏和显示与过滤项目,重新排序和整理甚至更多。
  • Super Gestures jQuery 插件可以实现鼠标手势的功能。
  • MouseWheel 是由Brandon Aaron开发的jQuery插件,用于添加跨浏览器的鼠标滚轮支持。
  • AutoSuggest jQuery 插件可以让你添加一些自动完成的功能。
  • qTip 一个漂亮的jQuery 的工具提示插件,这个插件功能相当强大。
  • jQuery Charts and graphic 用来制作图表。
  • jQuery Tools– The missing UI library

其它 jQuery 资源

HTML5 视频播放器

  • ★ Popcorn.js 是一个HTML5 Video框架,它提供了易于使用的API来同步交互式内容,让操作HTML5 Video元素的属性,方法和事件变得简单易用。 (来自Mozilla)
  • LeanBack Player HTML5视频播放器,没有依赖任何JavaScript框架。支持全屏播放,音量控制,在同一个页面中播放多个视频。 (来自Google)
  • Vid.ly 为你上传的视频提供转换功能,并且为转换后的视频创建一个短网址。通过Vid.ly,让你的视频可以在14种不同的浏览器和设备上播放,不需要再去考虑将 要浏览视频的人使用什么设备了,以避免各各软件巨头之间的利益之争带来了不兼容,给用户带来了巨大的困扰,短网址让你可以通过Twitter、 Facebook等方式方便分享视频。Vid.ly还可以通过html代码嵌入到其他网页中。Vid.ly免费帐户空间为1GB,免费帐户也没有播放或浏 览限制。

JavaScript 音频处理与可视化效果

  • ★ 使用HTML5 和 Flash, SoundManager V2 只用单一API的提供了可靠,简单和强大的跨平台的音频处理。
  • DSP, JavaScript的声音Digital Signal Processing
  • The Radiolab Hyper Audio Player v1, 带给你 WNYC Radiolab, SoundCloud 和 Mozilla Drumbeat
  • jPlayer, 一个 jQuery HTML5 音频/ 视频库,功能齐全的API

JavaScript 图形 和 3D

  • ★ Processing.js是一个开放的编程语言,在不使用Flash或Java小程序的前提下, 可以实现程序图像、动画和互动的应用。其使用Web标准,无需任何插件。
  • ★ Javascript 3D 引擎: ThreeJS 由 Mr Doob 开发,一个轻量级的 3D 引擎,不需要了解细节,傻瓜都能使用。这个引擎可以使用<canvas>, <svg> 和 WebGL.
  • Shader Toy, 一款使用WebGL的在线着色器编辑器(2D/3D). 基于在线的应用架构使您无需下载任何软件即可开始体验. Shader Toy包含大量实用着色器, 诸如光线追踪, 场景距离渲染, 球体, 隧道, 变形, 后期处理特效等.
  • PhiloGL, Sencha的PhiloGL是首个WebGL开发工具之一,提供了高水准的功能,来构建WebGL应用。Sencha创建了几个演示,来描述框架交互式3D虚拟化的能力,比如3D view of global temperature changes
  • WebGL Inspector 你就Firebug等Web调试工具一样,这个是 WebGL的调试工具。
  • WebGL frameworks 由 Khronos Group 收集的一个WebGL框架列表。
  • EaselJS, 一个使用html5的canvas的 JavaScript 库. Sources.
  • JavaScript Game Frameworks 免费的JS游戏框架列表。另,可参看 JS游戏框架列表
  • Raphaël是一个小型的JavaScript 库,用来简化在页面上显示向量图的工作。你可以用它在页面上绘制各种图表、并进行图片的剪切、旋转等操作。参看Javascript向量图Lib–Raphaël
  • jQuery SVG 插件让你可以了 SVG canvas 进行交互。
  • Google chart tools –  参看本站的使用Google API做统计图
  • Arbor.js, 是一个利用webworkers和jQuery创建的数据图形可视化JavaScript框架。它为图形组织和屏幕刷新处理提供了一个高效、力导向布局算法。

JavaScript 浏览器接口 (HTML5)

  • ★ Modernizr – 是一个专为HTML5 和CSS3 开发的功能检测类库,可以根据浏览器对HTML5 和CSS3 的支持程度提供更加便捷的前端优化方案.Sources. 一个有用的列表 cross-browser Polyfills
  • HTML5Shiv : 该项目的目的是为了让IE 能识别HTML5 的元素。
  • Polyfills : 这个项目收集了一些代码片段其用Javascript支持不同的浏览器的特别功能,有些代码需要Flash。
  • YepNopeJS : 一个异步的条件式的加载器。Sources.
  • jQuery CSS3 Finalise : 是否厌倦了为每一个浏览器的CSS3属性加前缀?
  • ★ Amplify.js :一套用于web应用数据管理和应用程序通讯的 jQuery 组件库。 提供简单易用的API接口。Amplify的目标是通过为各种数据源提供一个统一的程序接口简化各种格式数据的数据处理。Amplify的存储组件使用 localStorage 和 sessionStorage标准处理客户端的存储信息,对一些老的浏览器支持可能有问题。Amplify’为jQuery的ajax方法request 增加了一些额外的特性。 Sources.
  • History.js 优美地支持了HTML5 History/State APIs
  • Socket.IO Web的socket编程。

JavaScript 工具

  • ★  {{mustaches}} 小型的 JavaScript 模板引擎。
  • json:select(), CSS式的JSON选择器
  • HeadJS, 异步JavaScript装载。其最大特点就是不仅可以按顺序执行还可以并发装载载js。
  • JsDoc Toolkit是一款辅助工具,你只需要根据约定在JavaScript 代码中添加相应的注释,它就可以根据这些注释来自动生成API文档。
  • Responsive image, 一个试验性的项目,用来处理responsive layouts 式的图片。
  • UglifyJS是基于NodeJS的Javascript语法解析/压缩/格式化工具,它支持任何CommonJS模块系统的Javascript平台。
  • Dhteumeuleu, 交互式的 DOM 脚本和DHTML 的开源演示。
  • Backbone是 一个前端 JS 代码 MVC 框架,被著名的 37signals 用来构建他们的移动客户端。它不可取代 Jquery,不可取代现有的Template 库。而是和这些结合起来构建复杂的 web 前端交互应用。如果项目涉及大量的 javascript 代码,实现很多复杂的前端交互功能,首先你会想到把数据和展示分离。使用 Jquery 的 selector 和 callback 可以轻松做到这点。但是对于富客户端的WEB应用大量代码的结构化组织非常必要。Backbone 就提供了 javascript 代码的组织的功能。Backbone 主要包括 models, collections, views 和 events, controller 。

客户端和模拟器

CSS3 和 字库

Website (FULL) 模板

  • ★ HTML5 Boilerplate 是一个HTML5 / CSS / js模板,是实现跨浏览器正常化、性能优化,稳定的可选功能如跨域Ajax和Flash的最佳实践。 项目的开发商称之为技巧集合,目的是满足您开发一个跨浏览器,并且面向未来的网站的需求。 Sources.
  • HTML5 starter pack 是一个干净的和有组织的目录结构,其可适合很多项目,还有一些很常用的文件,以及简单的Photoshop设计模板。
  • ★ Initializr 是一个HTML5 模板生成器,其可以帮你在15秒内创建一个HTML5的项目。
  • Animated Portfolio Gallery教程
  • Slick MobileApp Website 如果通过 jQuery 和 CSS 制作一个手机应用的网站。
  • RSS Reader 如果通过 jQuery Mobile 创建一个RSS Reader
  • Single Page Applications 使用jQuery的朋友们 (Backbone, Underscore, …)创建单一页面。
  • Google TV Optimized Templates, 传统电视已经开始和网路融合,但现阶段产业仍然正在摸索之中,为此将来的网页亦会有结构上的改变。Google TV Optimized Templates是 一个用HTML/JavaScript制成的开源软体,一如其名是一个对Google TV作出了最佳化的的网页范本,其特色是以遥控器作为操作的前提,令使用者无需输入任何文字就可以进行控制。未来除了会有专用遥控器外,还会采用智能手机 透过W-iFi控制Google TV的方法。Optimized Templates的界面中左方会展示分类,右方会显示该分类下的影片截图,影片播放、切换、全画面表示都可透过键盘上的方向键、Backspace或 Enter等键完成,方便今后的网站开发人员借镜。HTML5 版的模板使用了 Google TV UI library, jQuery  和 Closure 。

(全文完)

[转载]条码扫描二维码扫描——ZXing android 源码简化

mikel阅读(1062)

[转载]条码扫描二维码扫描——ZXing android 源码简化 – indexRoad – 博客园.

前言

最近公司的Android项目需要用到摄像头做条码或二维码的扫描,Google一下,发现一个以Apache License 2.0 开源的 ZXing项目。Zxing项目里的Android实现太过复杂多余东西太多,得对其进行简化。

前提条件

下载源代码:点击这里

编译核心库:Zxing的主页上有介绍具体步骤,大家也可以参照这篇博文:android 条码识别软件开发全解析(续2详解绝杀!)

导入项目

打开Eclipse 导入 源码中的 Android 项目,然后右击项目 选择“Build path”——》”Add External Archives” 把核心库 core.jar文件加入到项目中。

此时编译一下项目,会发现报错,“ Multiple substitutions specified in non-positional format; did you mean to add the formatted=”false” attribute?”之类的。打开raw 下的Values 发现错误是在一个<String>上。这里把 “preferences_custom_product_search_summary” 里的  %s  %f  全部都改成  %1$s  %1$f(因为我们用不到多国语言,建议只保留默认的Value ,其他全部删除)。

原因:由于新的SDK采用了新版本的aapt(Android项目编译器),这个版本的aapt编译起来会比老版本更加的严格,然后在Android最新的开发文档的描述String的部分,已经说明如何去设置 %s 等符号

“If you need to format your strings using String.format(String, Object…) , then you can do so by putting your format arguments in the string resource. For example, with the following resource:

<string name=”welcome_messages”>Hello, %1$s! You have %2$d new messages.</string>

In this example, the format string has two arguments: %1$s is a string and %2$d is a decimal number. You can format the string with arguements from your application…“

经过以上步骤后项目应该就可以运行了。

但是ZXing的android项目东西太多了,有很多是我们不需要的,得新建另一个项目简化它。

简化

在开始前大致介绍一下简化ZXing需要用到各个包 、类的职责。

  • CaptureActivity。这个是启动Activity 也就是扫描器(如果是第一安装,它还会跳转到帮助界面)。
  • CaptureActivityHandler 解码处理类,负责调用另外的线程进行解码。
  • DecodeThread 解码的线程。
  • com.google.zxing.client.android.camera 包,摄像头控制包。
  • ViewfinderView 自定义的View,就是我们看见的拍摄时中间的框框了。

新建另一个项目

新建另一个项目将启动的Activity命名为CaptureActivity,并导入核心库。项目新建完成后我们打开 CaptureActivity 的布局文件,我这里为main。把里面的XML修改为:


可以看到在XML里面用到了 ViewfinderView 自定义view 。所以新建一个View 的包,然后把:ViewfinderView 和 ViewfinderResultPointCallback 靠到里面(记得对应修改XML里面的包)。

打开 CaptureActivity 覆盖 onCreate 方法:

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//初始化 CameraManager
CameraManager.init(getApplication());

viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
txtResult = (TextView) findViewById(R.id.txtResult);
hasSurface = false;
inactivityTimer = new InactivityTimer(this);
}

这里调用到的 CameraManager 类是控制摄像头的包里的类。新建一个camera包把:com.google.zxing.client.android.camera 里面的类全部拷入,另外我把PlanarYUVLuminanceSource也拷入到这个包里面。根据错误的提示来修正代码,主要是修改正包结构。(整 个简化的流程都是如此:“根据错误提示,修改代码”)。

在修改的过程中,有很多是关于R 资源的问题,在此我们需要将Values  里面的两个xml资源文件拷入项目中:colos.xml 和ids.xml 。 ctrl+b 一下看看error 是不是少了很多。在CameraManager中有些地方需要用到项目的配置,这里需要把配置直接写入代码中:

// SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
//是否使用前灯
// if (prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false)) {
// FlashlightManager.enableFlashlight();
// }
FlashlightManager.enableFlashlight();

使用摄像头需要加入相应的权限:






当View 和 camera 包里的错误修正完成后,我们继续来看CaptureActivity。

覆盖onResume方法初始化摄像头:

@Override
protected void onResume() {
super.onResume();
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
if (hasSurface) {
initCamera(surfaceHolder);
} else {
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
decodeFormats = null;
characterSet = null;

playBeep = true;
AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE);
if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
playBeep = false;
}
initBeepSound();
vibrate = true;
}

private void initCamera(SurfaceHolder surfaceHolder) {
try {
CameraManager.get().openDriver(surfaceHolder);
} catch (IOException ioe) {
return;
} catch (RuntimeException e) {
return;
}
if (handler == null) {
handler = new CaptureActivityHandler(this, decodeFormats,
characterSet);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {

}

@Override
public void surfaceCreated(SurfaceHolder holder) {
if (!hasSurface) {
hasSurface = true;
initCamera(holder);
}

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
hasSurface = false;

}

initCamera () 方法用于初始化摄像头,如果排除了所有的error ,运行项目时就可以看到大致扫描界面了。 surfaceHolder.addCallback(this);表示让CaptureActivity实现其callback接口。

handler = new CaptureActivityHandler(this, decodeFormats, characterSet) 用于进行扫描解码处理。
解码

上面的步骤主要都是用于对摄像头的控制,而解码的真正工作入口是在CaptureActivityHandler 里面的。新建一个Decoding包把以下文件拷入包中:

CaptureActivityHandler
DecodeFormatManager
DecodeHandler
DecodeThread
FinishListener
InactivityTimer
Intents

由于我们的包结构和Zxing 项目的有所不同所以需要注意一下类的可访问性

同样开始ctrl+B 编译一下,然后开始修正错误。

在CaptureActivityHandler 里 把 handleMessage 里的部分方法先注释掉如:“decode_succeeded ”分支,这是解码成功时调用 CaptureActivity 展示解码的结果。

在DecodeThread 类里,修改部分涉及Preference配置的代码:

DecodeThread(CaptureActivity activity,
Vector decodeFormats,
String characterSet,
ResultPointCallback resultPointCallback) {

this.activity = activity;
handlerInitLatch = new CountDownLatch(1);

hints = new Hashtable(3);

// // The prefs can't change while the thread is running, so pick them up once here.
// if (decodeFormats == null || decodeFormats.isEmpty()) {
// SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
// decodeFormats = new Vector();
// if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_1D, true)) {
// decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
// }
// if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_QR, true)) {
// decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
// }
// if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_DATA_MATRIX, true)) {
// decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
// }
// }
if (decodeFormats == null || decodeFormats.isEmpty()) {
decodeFormats = new Vector();
decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);

}

hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);

if (characterSet != null) {
hints.put(DecodeHintType.CHARACTER_SET, characterSet);
}

hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback);
}

这里是设置 解码的类型,我们现在默认将所有类型都加入。

错误类型基本上都是:包结构、PreferencesActivity 的配置 、类可访问性的问题。根据错误提示耐心把错误解决。
返回解码结果

还记得在 CaptureActivityHandler 的 messagehandler 里注销掉的Case分支吗?现在CaptureActivity 里实现它。

public void handleDecode(Result obj, Bitmap barcode) {
inactivityTimer.onActivity();
viewfinderView.drawResultBitmap(barcode);
playBeepSoundAndVibrate();
txtResult.setText(obj.getBarcodeFormat().toString() + ":"
+ obj.getText());
}

最后

ZXing的简化已基本完成,有几位是可以运行成功的?呵呵。

下面是CaptureActivity的源码:

public class CaptureActivity extends Activity implements Callback {

private CaptureActivityHandler handler;
private ViewfinderView viewfinderView;
private boolean hasSurface;
private Vector decodeFormats;
private String characterSet;
private TextView txtResult;
private InactivityTimer inactivityTimer;
private MediaPlayer mediaPlayer;
private boolean playBeep;
private static final float BEEP_VOLUME = 0.10f;
private boolean vibrate;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//初始化 CameraManager
CameraManager.init(getApplication());

viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
txtResult = (TextView) findViewById(R.id.txtResult);
hasSurface = false;
inactivityTimer = new InactivityTimer(this);
}

@Override
protected void onResume() {
super.onResume();
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
if (hasSurface) {
initCamera(surfaceHolder);
} else {
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
decodeFormats = null;
characterSet = null;

playBeep = true;
AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE);
if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
playBeep = false;
}
initBeepSound();
vibrate = true;
}

@Override
protected void onPause() {
super.onPause();
if (handler != null) {
handler.quitSynchronously();
handler = null;
}
CameraManager.get().closeDriver();
}

@Override
protected void onDestroy() {
inactivityTimer.shutdown();
super.onDestroy();
}

private void initCamera(SurfaceHolder surfaceHolder) {
try {
CameraManager.get().openDriver(surfaceHolder);
} catch (IOException ioe) {
return;
} catch (RuntimeException e) {
return;
}
if (handler == null) {
handler = new CaptureActivityHandler(this, decodeFormats,
characterSet);
}
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {

}

@Override
public void surfaceCreated(SurfaceHolder holder) {
if (!hasSurface) {
hasSurface = true;
initCamera(holder);
}

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
hasSurface = false;

}

public ViewfinderView getViewfinderView() {
return viewfinderView;
}

public Handler getHandler() {
return handler;
}

public void drawViewfinder() {
viewfinderView.drawViewfinder();

}

public void handleDecode(Result obj, Bitmap barcode) {
inactivityTimer.onActivity();
viewfinderView.drawResultBitmap(barcode);
playBeepSoundAndVibrate();
txtResult.setText(obj.getBarcodeFormat().toString() + ":"
+ obj.getText());
}

private void initBeepSound() {
if (playBeep &amp;&amp; mediaPlayer == null) {
// The volume on STREAM_SYSTEM is not adjustable, and users found it
// too loud,
// so we now play on the music stream.
setVolumeControlStream(AudioManager.STREAM_MUSIC);
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setOnCompletionListener(beepListener);

AssetFileDescriptor file = getResources().openRawResourceFd(
R.raw.beep);
try {
mediaPlayer.setDataSource(file.getFileDescriptor(),
file.getStartOffset(), file.getLength());
file.close();
mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
mediaPlayer.prepare();
} catch (IOException e) {
mediaPlayer = null;
}
}
}

private static final long VIBRATE_DURATION = 200L;

private void playBeepSoundAndVibrate() {
if (playBeep &amp;&amp; mediaPlayer != null) {
mediaPlayer.start();
}
if (vibrate) {
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
vibrator.vibrate(VIBRATE_DURATION);
}
}

/**
* When the beep has finished playing, rewind to queue up another one.
*/
private final OnCompletionListener beepListener = new OnCompletionListener() {
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.seekTo(0);
}
};

简化过的包结构图:

简化后的ZXing 更加方便我们了解ZXing项目 是如何解码的。只要仔细查看源码,进行单点跟踪调试,相信大家很容易能理解。

[转载]Android从SDCard中取得图片并设置为桌面背景

mikel阅读(1106)

[转载]Android从SDCard中取得图片并设置为桌面背景 – 老牛啊 – 博客园.

1、 把背景图片push到SDCard中
adb push MM-320×480.png /sdcard/
确认是否已经存在了,可以到SDCard看一下:
adb shell
cd sdcard
ls
可以看到刚才上传的图片:
2、编写Activity程序
  public static final String  TAG       = "WallpaperActivity";

    /**
     * 背景图片名称
     */
    private static final String FILE_NAME = "MM-320x480.png";

    /** 
     * @see android.app.Activity#onCreate(android.os.Bundle)
     */
    public void onCreate(Bundle cycle) {
        super.onCreate(cycle);
        super.setContentView(R.layout.wallpaper);
        
        // 取得背景图片
        Bitmap wallpaper = this.getWallpager();

        // 设置桌面背景
        this.putWallpaper(wallpaper);
    }

    /**
     * 取得SDCard中的背景图片
     */
    private Bitmap getWallpager() {
        // SDCard的路径,也就是“/sdcard/”
        File root = Environment.getExternalStorageDirectory();
        // MM图片
        File wall = new File(root, FILE_NAME);
        // MM图片路径
        String path = wall.getAbsolutePath();

        Log.d(TAG, "MM文件路径为:" + path);

        return BitmapFactory.decodeFile(path);
    }

    /**
     * 设置桌面背景
     */
    private void putWallpaper(Bitmap bitmap) {
        try {
            WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
            wallpaperManager.setBitmap(bitmap);
        } catch (IOException e) {
            String msg = "设置桌面背景发生异常:" + e.getLocalizedMessage();
            Log.e(TAG, "设置桌面背景发生异常!", e);
            Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
        }
    }

3、增加权限
AndroidManifest.xml文件中增加设置桌面背景权限:

<!-- 设置桌面背景的权限 -->
<uses-permission android:name="android.permission.SET_WALLPAPER" />

4、运行程序
运行程序,再回到桌面,背景已经改变了。