DFdou's Blog Life is short,Be yourself.

2508/100

Android-Multi-Touch~

忙啊忙……直接贴码了,是个挺简单的过程:

public boolean onTouch(View v, MotionEvent event)
{
   for( int i = 0; i < event.getPointerCount(); i++ ){
         float x = event.getX(i);
         float y = event.getY(i);
   }
   return true;
}

只在G3 2.1Rom上测试过,其他,不知道呀么不知道~~
发现自己越来越不严谨=,=

908/100

八款开源Android游戏引擎

听说原产地是CSDN,有兴趣的自己找下原出处吧,以下是内容:

很多初学Android游戏开发的朋友,往往会显得有些无所适从,他们常常不知道该从何处入手,每当遇到自己无法解决的难题时,又往往会一边羡慕于 iPhone下有诸如Cocos2d-iphone之类的免费游戏引擎可供使用,一边自暴自弃的抱怨Android平台游戏开发难度太高,又连个像样的游 戏引擎也没有,甚至误以为使用Java语言开发游戏是一件费力不讨好且没有出路的事情。

事实上,这种想法完全是没有必要且不符合实际的,作为能和苹果iOS分庭抗礼的Android(各种意义上),当然也会有相当数量的游戏引擎存在。仅仅因为我们处于这个狭小的天地间,与外界接触不够,所以对它们的存在茫然不知罢了。

下面我就罗列出八款常见的Android游戏引擎,以供有需要者参考(收费,下载量过小,不公布源码,以及鄙人不知道(-_-)的引擎不在此列)。

1、Angle

Angle是一款专为Android平台设计的,敏捷且适合快速开发的2D游戏引擎,基于OpenGL ES技术开发。该引擎全部用Java代码编写,并且可以根据自己的需要替换里面的实现,缺陷在于文档不足,而且下载的代码中仅仅包含有少量的示例教程。

最低运行环境要求不详。

项目地址:http://code.google.com/p/angle/

2、Rokon

rokon是一款Android 2D游戏引擎,基于OpenGL ES技术开发,物理引擎为Box2D,因此能够实现一些较为复杂的物理效果,该项目最新版本为 2.0.3 (09/07/10)。总体来说,此引擎最大的优点在于其开发文档相当之完备,并且项目作者对反馈Bug的修正非常之神速,所以该框架的使用在目前也最为 广泛,有人干脆将它称为Cocos2d-iPhone引擎的Android版(业务逻辑和编码风格上也确实很像)。附带一提,国内某个需要注册会员才能下 载的Android游戏框架衍生于此框架,所以大家也不要刻板的认为收费便一定是好的,免费就一定不好。

最低运行环境要求为Android 1.5。

项目地址:http://code.google.com/p/rokon/

3、LGame

LGame是一款国人开发的Java游戏引擎,有Android及PC(J2SE)两个开发版本,目前最高版本同为0.2.6(31/07/10)。其底 层绘图器LGrpaphics封装有J2SE以及J2ME提供的全部Graphics API(PC版采用Graphics2D封装,Android版采用Canvas模拟实现),所以能够将J2SE或J2ME开发经验直接套用其中,两版本 间主要代码能够相互移植。Android版内置有Admob接口,可以不必配置XML直接硬编码Admob广告信息。

该引擎除了基本的音效、图形、物理、精灵等常用组件以外,也内置有Ioc、xml、http等常用Java组件的封装,代价是jar体积较为庞大,PC版 已突破1.2MB,Android版有所简化也在500KB左右。此外,该引擎还内置有按照1:1实现的J2ME精灵类及相关组件,可以将绝大多数 J2ME游戏平移到Android或PC版中。唯一遗憾的是,该项目作者是个极其懒惰的家伙,开发文档从去年说到今年依旧没有提供,只有游戏示例可供下 载。

最低运行环境要求为Android 1.1。

项目地址:http://code.google.com/p/loon-simple/

4、AndEngine

andengine同样是一款基于OpenGL ES技术的Android游戏引擎,物理引擎同样为Box2D(标配|||)。该框架性能普通,文档缺乏,但示例较为丰富。

下载地址(未直接提供jar下载,源码可通过svn提取):http://code.google.com/p/andengine/

最低运行环境要求不详。

项目地址:http://code.google.com/p/rokon/

5、libgdx

libgdx是一款基于OpenGL ES技术开发的Android游戏引擎,支持Android平台下的2D游戏开发,物理引擎采用Box2D实现。单就性能角度来说,堪称是一款非常强大的 Android游戏引擎,但缺陷在于精灵类等相关组件在使用上不够简化,而且文档也较为匮乏。

最低运行环境要求不详。

项目地址:http://code.google.com/p/libgdx/

6、jPCT

jPCT是一款基于OpenGL技术开发的3D图形引擎(PC环境为标准OpenGL,Android为OpenGL ES), 以Java语言为基础的,拥有功能强大的Java 3D解决方案。该引擎与LGame(此为2D游戏引擎)相类似,目前拥有PC(J2SE)以及Android两个开发版本。

jPCT的最大优势之一,就在于它惊人的向下兼容性。在PC环境中,jPCT甚至可以运行在JVM1.1环境之中,因为jPCT内部提供的图形渲染接口完 全符合所有的Java 1.1规范(就连已经消失的Microsoft VM乃至更古老的Netscape 4 VM也不例外)。

最低运行环境要求为Android 1.5。

项目地址:http://www.jpct.net/jpct-ae/

7、Alien3d

Alien3d是一款体积非常之小的Android 3D游戏引擎,基于OpenGL ES技术开发。为了压缩体积,它根据不同功能采用多jar方式发布(包括alien3d-engine.jar,alien3d- tiled.jar,alien3d-sprites.jar,alien3d-shapes.jar,alien3d- particles2d.jar,),事实上它的核心文件大约只有40KB,所有相关jar的总和也不足150KB。

最低运行环境要求为Android 1.5。

项目地址:http://code.google.com/p/alien3d/

8、Catcake

Catcake是一款跨平台的Java 3D图形引擎,目前支持PC(J2SE)及Android环境运行(已有iPhone版规划)。该引擎在易用性和运行性能上皆有出色的表现,支持常见的游戏开发功能,诸如精灵动画,音频处理和视频播放等。

最低运行环境要求为Android 1.6。

项目地址:http://code.google.com/p/catcake/

Tagged as: No Comments
2207/101

《程序员》精彩推荐:Android程序创意过滤与失败经验谈

via www.programmer.com.cn on 7/21/10 文/ 刘铁锋

从2008年底开始,我就在Android上进行程序开发探索。随着时间的推移,我越来越不敢妄自预测或者假设程序创意一定会成功,更多地发现用户的期望以及需求和事先预想很难一致。在一年半的开发过程中,尝试了各种不同的方法和思路来进行程序创意规划和试错。至今,依然失败的教训居多,侥幸成功的很少。因此,我将在本文中分享所经历的创意过滤经验以及失败教训。

思路转换的失败

在转入Android开发时,我的相关工作经验都是在大型基础平台上做程序开发。针对的用户群体动辄就是全球目标用户,在商业判断和分析上,最基础的一个考量就是用户群体和业务模式的总量的收益是否足够大,对用户群体的研究和商业判断分析完全根据市场分析报告和数据来做判断。因此,不可避免地在程序创意思路上会沿用以前的工作思路和分析方法。

在考虑Android上的创意的同时,不自觉地就考虑和分析了如下几个方面的问题:

1. 是否为用户所必需?
2. 技术上是否领先?
3. 程序的粘性是否足够?
4. 用户群体是否足够大?

因此,沿用这个思路,不可避免地就会往大的应用和大的服务上去思考和做出判断。

经过多方的讨论,找到了一个切入点:在用户联系人信息上同时显示出用户在社会网络(比如Facebook/Twitter)上的同步更新,并加上相关的操作是不错的想法。

理由如下:

1. 联系人是手机用户需要的必不可少的功能,绝对必须使用。
2. 技术上由于需要实现和系统联系人类似的功能,工作量不会小。如果加上未来在云端的备份,技术门槛也不会太低。
3. 绑定用户的社会网络信息,这个粘性理论上和用户使用社会网络的粘性一样。
4. 用户群体为所有社交网络的用户,考虑到Google手机的用户都是技术的爱好者和早期技术推广者,那么,基本上大部分Android用户都会使用。

按照这个思考方式分析下来,毫无疑问,这个想法一点也不差,能够相当完美地达到预期的规划。

因此,我们投入了3位开发工程师和1位产品经理,一共工作了3个月的时间,产品才初步成型,产品的源代码接近2MB,最后编译出来的程序接近4MB。
经过了痛苦的研发过程,产品出来之后,结果却令人大跌眼镜:

1. 程序包过大。用户根本不愿意下载,下载量非常惨淡。
2. 用户完全搞不懂这个程序的目的和用法。程序的命令以及描述非常难表达,并且程序需要绑定用户的社交网络账号,才可以显示信息。没有绑定之前,看不到任何特别信息,也体会不到程序的作用。很多用户在上手时看到需要绑定,便开始疑惑了。
3. 最终有用户搞明白了程序的用法,觉得想法不错。但程序的稳定性和性能遇到的了严重的瓶颈。尽管在其他平台开发经验不错,但是毕竟这是一个新的平台,并且程序操作相当复杂,用户依然选择了放弃使用。
4. 下载量不高,评分又逐渐降低,程序就在排行榜的榜单上渐渐消失了。
5. 惨淡的结果,让所有参与人员都开始沮丧,觉得这并不是一个好的想法。后来在iPhone上发现了类似的程序,从销售情况来看,表现同样不够好。再后来,Moto的Cliq基本上完整地把这个想法实现了,并作为一重大创新和卖点进行推出。

经过反复地反省和对比,初步得出了这样的失败教训:

1. 对于个人开发者和小型团队来说,不适合做过于基础的程序。操作的模式和理念上的创新与用户的接受度有相当的距离。这样的事情只有大公司才有财力和可能进行推广。比如说手机生产商,他们可以通过预置的方式进行推广。而对个人开发者来说,得先证明你的想法是成功的,不能假设一个会成功的需求和应用,然后卖给设备厂商。
2. 个人开发者和小型团队不适合做大的程序,尤其是开发时间不要超过2个月。4个人,3个月的时间,对于一个小团队来说 ,是相当宝贵的。这不仅仅是时间和金钱的问题,更多的是信心问题。
3. 用户能否真正接受你的想法,是一个关键性的问题。设想和推导都很完美,唯独缺了用户是否真正喜欢和接受这一条,又没有方法进行快速地验证和试错,基本上不能成功。

因此,在开发者头脑风暴产生一个创意之后,要做的几个最主要的过滤在于:

1. 开发时间是否太长?
2. 开发的技术难度是否会过高,而导致不能实现或者质量不可靠?
3. 有怎样的办法来判断用户是否会喜欢?
有了这几个过滤条件,相信能够减少失败的几率,或者说能够Fail Fast(尽快失败),从而减少损失。

技术门槛的失败

在Android开发的过程中,除了大型的程序探索,我们也研究了些小程序来练手。有个同事提出Android上删除程序不方便,于是,找人花一天左右的时间做了一个叫Quick Uninstaller的程序。程序非常简单,启动之后显示所有程序图标,双击程序图标,即可删除该程序。想法以及难度,都不很独特。

但是,效果却出乎大家的意料。用户好评如潮,由于功能比较简单,用户基本上无需学习,加上又是先行者,产品质量非常稳定,没有任何“force close”(Android程序出现异常或者等待时间过长,会弹出“force close”的对话框)。用户毫不犹豫地直接打出5分,并且基本上没有任何低分出现过。

但是,好景不长。在一次Google清洗的过程中,因为一些版权问题,账号被Google封掉了。所有程序被强行下架。这个时候,竞争对手迅速上位,就是目前在排行榜前列的Uninstaller,而我们的程序则一落千丈,尽管现在在某个细分分类中还有一定的位置,但是相比排名最高的程序,已经相差很远了。

这也让我们多了一个失败的教训:

1. 技术门槛不高,不能保证你一直保持优势。对你来说简单的程序,对竞争对手来说,程序同样的简单。因此,你能做,别人也能做。在这一点上,其实竞争同样激烈。
2. 封账号的代价相当之大,基本上等于你的努力悉数尽毁。Don’t do evil。

因此,在这个案例中,增加了一个新的创意过滤条件:
程序的创意是否过于简单?如果过于简单,那么创意能够始终保持成功的机会不会太高。

依赖第三方资源的失败

在经历了前面的屡次失败之后,我们开始做些研究的工作。发现老外其实也很八卦,什么笑话、娱乐新闻等,接受程度很高。因此,我们就想到了FML(Fuck My Life)的网站,也就是老外比较热衷的糗事分享网站,每天有很多人会发布各种各样的糗事,文字最后均会以Fuck My Life结尾。
于是,想到如果在手机上有这样的客户端,用户可能会更加愿意用,尤其是在发生糗事的时候,忍不住就想分享出来,粘性也会足够。
基于以上考虑,我们投入力量,实现了一个功能比较完善的版本,不仅融合了此服务所应有的相关功能,同时还花了不少工夫,加上了好多自定义的功能。
经过一段时间的努力,在Entertainment分类上,排名进了前10名,印象中程序最好排到了第3名。

好景不长在,失败总会有。
这个时候,FML的官网发现了这个机会。他们觉得这是一个很好的想法,应该自己在Market上发布自己的官方程序。于是,他们干了这样的事情来清除竞争对手。他们直接向Google举报,说其它程序没有得到他们的授权。一次举报,竞争对手全部清干净了,于是他们的官方程序上线了。

这一次,得到了一个更加深刻的教训:

1. 不要过于依赖第三方资源。依赖第三方资源或者网站的名气,的确可能帮助你的程序受到很多关注,代价也同样存在,一旦人家开始动手举报,你连还手的机会都没有。
2. 不要选错第三方资源。很多的服务提供商是不开放的,尽管他们没有明确说明。同时还有很多服务提供商是充分开放的,比如Twitter就是一个非常开放的例子。选错了第三方资源,结果一样会失败。

因此,这里又多了一个创意过滤的条件:
是否依赖于第三方资源? 如果是,请尽快绕道离开,因为很难靠这个想法走太远。

胡乱模仿的失败
由于才疏学浅和关注面单一,想法总会有用完的时候。在尝试了很多自己的想法之后,很多人都会有想法来借鉴或者说抄袭App Store上排名靠前的程序。
但是,以我的经验和分析来看,这条路基本上不可行。

有以下几个方面的原因:

1. 画虎不成反类犬。如果是在人家创意上进行的功能改进,你还可能有一定的突破和机会。如果仅仅是抄袭,由于平台的不同,Android的控件和iPhone的程序控件相差太远,哪怕做出来程序类似,操作体验和程序的精致程度也和iPhone上程序相差甚远,往往就成为画虎不成反类犬。
2. 版权问题。老外的版权意识非常强,不仅仅是原作者非常关心,用户也很敏感。如果侥幸程序排到了前列,不仅会把原作者招惹过来,用户还会出来举报。一旦Google收到了举报邮件,基本上是杀无赦。反倒是偷鸡不成蚀把米。

因此,创意过滤中又多了一个条件:
创意是否有版权争议?如果是,尽快停止。失败只是时间的问题。

其他
总的来说,在我的探索过程中,成功的少,而失败的太多太多。在与Google打交道的过程中,依然有很多失败的教训可供分享。

1. Don’t do evil。美国人做事的方式非常直接,同时会默认你是善意的。对于Google来说,尤其如此。因此,在我尝试过的程序中,你可以任意发布你的程序到Google Market。但是,如果涉及到版权纠纷,不管是网站的所有者、原程序的开发者还是其它任何一种类型的版权纠纷,一旦举报到Google,轻者下架单个程序,重者封禁整个账号,并且下架所有程序。也就是说,一旦受到处罚,你就别想翻身了。因此,Don’t do evil。

2. Google的审查底线。尽管Google不做审查,但除了和版权争议相关的程序之外,哪怕是你自己的程序,依然有如下的禁区是不能碰的:

a. 不要使用任何Google相关的名义。程序名、开发者名都不能涉及到Google或者看起来类似Google的名称,否则Google不会予以通过。

b. 不要违反任何Google的开发者协议。需要仔细阅读Google的开发者协议,在不同时候Google的开发者协议会经常更新。因此,只要违反了任何Google开发者协议,当Google处罚到你的时候,基本上没有申辩机会。因此,务必要小心。

总结

在我开发的经验过程中,成功的经验不多,而失败的教训无数。哪怕如此,我坚信在移动互联网领域,依然存在这样或者那样的机会。也许不经意间你的一个创意就得到了用户的热捧,有幸跑到排行榜的前列,但是这需要足够多的精力和耐性来打磨你的产品,才不至于昙花一现。同时,也不能得意忘形,说不好,就会有各种各样的可能导致你失去优势。因此,移动领域的确是一个新的机会,但绝对不是一个能够随随便便抓住的机会。希望我的失败教训能够帮助到开发者,以此为鉴。

刘铁峰作者简介:刘铁锋,曾供职于微软亚洲研究院搜索技术中心,目前从事移动设备软件相关开发工作,关注Android、iPhone等相关开发技术以及App Store、Android Market等业界应用商店进展。

(本文来自《程序员》杂志10年05期)
《程序员》10年7月刊精彩内容预告:http://www.programmer.com.cn/3484/
《程序员》订阅:http://book.csdn.net/programmer/
-------------------------------------------------------------------------------------------------
最新有点忙,先转载了~~

Filed under: Android 1 Comment
1006/102

Admob-Mobile advertising and the iPhone

From http://blog.admob.com/2010/06/09/mobile-advertising-and-the-iphone/

Apple proposed new developer terms on Monday that, if enforced as written, would prohibit app developers from using AdMob and Google’s advertising solutions on the iPhone. These advertising related terms both target companies with competitive mobile technologies (such as Google), as well as any company whose primary business is not serving mobile ads. This change threatens to decrease – or even eliminate – revenue that helps to support tens of thousands of developers. The terms hurt both large and small developers by severely limiting their choice of how best to make money. And because advertising funds a huge number of free and low cost apps, these terms are bad for consumers as well.

Let’s be clear. This change is not in the best interests of users or developers. In the history of technology and innovation, it’s clear that competition delivers the best outcome. Artificial barriers to competition hurt users and developers and, in the long run, stall technological progress.

Since I started AdMob in 2006, I have watched competition in mobile advertising help drive incredible growth and innovation in the overall ecosystem. We’ve worked to help developers make money, regardless of platform – iPhone, Android, Palm Pre, Blackberry, Windows, and others. In the past four years, AdMob has helped tens of thousands of developers make money and build real businesses across multiple operating systems.

I’ve personally worked with many iPhone app developers around the world, including one who created a fun and simple game in the early days of the App Store. He built the app because he was interested in the challenge. He built this single app into a multi-million dollar advertising revenue stream with AdMob, hired a whole team, and turned a hobby into a real business.

We see these stories all the time. We want to help make more of them, so we’ll be speaking to Apple to express our concerns about the impact of these terms.

Omar

-----------------------------------------------------------------------------
应该要被告垄断了吧,水果,越来越专制了。

Tagged as: , 2 Comments
2104/101

Android-AS3的AStar复刻版

因为需要,所以直接把AS3版本的AStar复刻成了Java版,基本上什么都没改。
唉,让人比较无语的是Java里的ArrayList和Array咩有shift和unshift之类的常用函数的?
问了班里几个似乎在做Java的人,得到的答案=没有答案。
下边是复刻之后的代码:
AStar.java:

/**
 *
 */
package util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import android.util.Log;

/**
 * @author DFdou
 *
 */

public class AStar {
    // 待考察表
    private ArrayList<node> _open = new ArrayList</node><node>();
    // 已考察表
    private ArrayList</node><node> _closed = new ArrayList</node><node>();
    // 网格
    private Grid _grid;
    // 开始节点
    private Node _startNode;
    // 结束节点
    private Node _endNode;
    // 终点节点的数组
    private ArrayList</node><node> _path = new ArrayList</node><node>();
    // 曼哈顿估价函数,算横竖距离和
    //private Function _heuristic = manhattan;
    // 几何估价法,算直线距离
    // private var _heuristic:Function = euclidian;
    // 对角线估价法
    // private var _heuristic:Function=diagonal;
    // 直线前进代价
    private float _straightCost = 1.0f;
    // 对角线前进代价
    private float _diagCost = 1.414f;

    public AStar() {
    }

    // 8方向
    public boolean findPath(Grid grid) {
	_grid = grid;
	// 创建待考察列表
	_open.clear();
	// 创建已考察列表
	_closed.clear();
	// 起点
	_startNode = _grid.getStartNode();
	// 终点
	_endNode = _grid.getEndNode();
	_startNode.g = 0;
	// 选一个估价函数,传入起点
	_startNode.h = manhattan(_startNode);
	_startNode.f = _startNode.g + _startNode.h;
	// 返回寻路结果
	return search();
    }

    public boolean search() {
	// 将起点节点设为当前节点
	Node node = _startNode;
	// 如果木有到达目标节点
	while (node != _endNode) {
	    // 循环的节点范围,不需要检测grid范围以外的节点
	    int startX = Math.max(0, node.x - 1);
	    int endX = Math.min(_grid.getNumCols() - 1, node.x + 1);
	    int startY = Math.max(0, node.y - 1);
	    int endY = Math.min(_grid.getNumRows() - 1, node.y + 1);
	    for (int i = startX; i < = endX; i++) {
		for (int j = startY; j <= endY; j++) {
		    // 尝试节点
		    Node test = _grid.getNode(i, j);
		    // 尝试节点为当前节点,或者为不可通过的节点,或者临接节点都不能通过那么就跳过该节点
		    if (test == node || !test.walkable
			    || !_grid.getNode(node.x, test.y).walkable
			    || !_grid.getNode(test.x, node.y).walkable) {
			continue;
		    }
		    float cost = _straightCost;
		    // 如果不在同直线距离上,就是对角线了~
		    if (!((node.x == test.x) || (node.y == test.y))) {
			cost = _diagCost;
		    }
		    // 计算g值
		    double g = node.g + cost * test.costMultiplier;
		    // 计算h值
		    double h = manhattan(test);
		    // 相加得到f
		    double f = g + h;
		    // 如果测试点已经在待考察列表或者已考察列表里,就比较已考察的结果是否比当前结果大,是的话就重新赋值,也就是说找到了更优的点
		    if (isOpen(test) || isClosed(test)) {
			if (test.f > f) {
			    test.f = f;
			    test.g = g;
			    test.h = h;
			    test.parent = node;
			}
			// 测试点不再待考察列表中,赋值,设置父节点,加入待考察列表
		    } else {
			test.f = f;
			test.g = g;
			test.h = h;
			test.parent = node;
			_open.add(test);
		    }
		}
	    }
	    // 根据f进行排序,最后一个是f值最小的
	    // _open.sortOn("f", Array.NUMERIC);
	    Comparator comp = new NodeFComparator();
	    Collections.sort(_open, comp);
	    // 作为当前节点
	    // node = _open.shift();
	    node = _open.get(0);
	    _open.remove(0);
	    _open.trimToSize();
	}
	buildPath();
	return true;
    }

    // 4方向
    public boolean findPath4(Grid grid) {
	_grid = grid;
	// 创建待考察列表
	_open.clear();
	// 创建已考察列表
	_closed.clear();
	// 起点
	_startNode = _grid.getStartNode();
	// 终点
	_endNode = _grid.getEndNode();
	_startNode.g = 0;
	// 选一个估价函数,传入起点
	_startNode.h = manhattan(_startNode);
	_startNode.f = _startNode.g + _startNode.h;
	// 返回寻路结果
	return search4();
    }

    public boolean search4() {
	// 将起点节点设为当前节点
	Node node = _startNode;
	// 如果木有到达目标节点
	while (node != _endNode) {
	    // 循环的节点范围,不需要检测grid范围以外的节点
	    int startX = Math.max(0, node.x - 1);
	    int endX = Math.min(_grid.getNumCols() - 1, node.x + 1);
	    int startY = Math.max(0, node.y - 1);
	    int endY = Math.min(_grid.getNumRows() - 1, node.y + 1);
	    for (int i = startX; i < = endX; i++) {
		for (int j = startY; j <= endY; j++) {
		    // 尝试节点
		    Node test = _grid.getNode(i, j);
		    // 尝试节点为当前节点,或者为不可通过的节点,或者临接节点都不能通过那么就跳过该节点
		    // PS:在四方向寻路情况下跳过对角线点
		    if (test == node || !test.walkable
			    || !_grid.getNode(node.x, test.y).walkable
			    || !_grid.getNode(test.x, node.y).walkable
			    || Math.abs(i - node.x) + Math.abs(j - node.y) > 1) {
			continue;
		    }
		    float cost = _straightCost;
		    // 如果不在同直线距离上,就是对角线了~
		    if (!((node.x == test.x) || (node.y == test.y))) {
			cost = _diagCost;
		    }
		    // 计算g值
		    double g = node.g + cost * test.costMultiplier;
		    // 计算h值
		    double h = manhattan(test);
		    // 相加得到f
		    double f = g + h;
		    // 如果测试点已经在待考察列表或者已考察列表里,就比较已考察的结果是否比当前结果大,是的话就重新赋值,也就是说找到了更优的点
		    if (isOpen(test) || isClosed(test)) {
			if (test.f > f) {
			    test.f = f;
			    test.g = g;
			    test.h = h;
			    test.parent = node;
			}
			// 测试点不再待考察列表中,赋值,设置父节点,加入待考察列表
		    } else {
			test.f = f;
			test.g = g;
			test.h = h;
			test.parent = node;
			_open.add(test);
		    }
		}
	    }

	    // 当前节点已经考察过了,所以就加入已考察列表
	    _closed.add(node);
	    // 检查待考察表里面有没有节点,没有就意味着没有可行的路径
	    if (_open.size() == 0) {
		return false;
	    }
	    // 根据f进行排序,最后一个是f值最小的
	    // _open.sortOn("f", Array.NUMERIC);
	    Comparator comp = new NodeFComparator();
	    Collections.sort(_open, comp);
	    // 作为当前节点
	    // node = _open.shift();
	    node = _open.get(0);
	    _open.remove(0);
	    _open.trimToSize();
	}
	buildPath();
	return true;
    }

    // 建立路径
    private void buildPath() {
	_path.clear();
	Node node = _endNode;
	_path.add(node);
	while (node != _startNode) {
	    node = node.parent;
	    // _path.unshift(node);
	    _path.add(0, node);
	}
    }

    public ArrayList</node><node> getPath() {
	return _path;
    }

    private boolean isOpen(Node node) {
	int len = _open.size();
	for (int i = 0; i < len; i++) {
	    if (_open.get(i) == node) {
		return true;
	    }
	}
	return false;
    }

    private boolean isClosed(Node node) {
	int len = _closed.size();
	for (int i = 0; i < len; i++) {
	    if (_closed.get(i) == node) {
		return true;
	    }
	}
	return false;
    }

    private double manhattan(Node node) {
	return Math.abs(node.x - _endNode.x) * _straightCost
		+ Math.abs(node.y + _endNode.y) * _straightCost;
    }

    private double euclidian(Node node) {
	float dx = node.x - _endNode.x;
	float dy = node.y - _endNode.y;
	return Math.sqrt(dx * dx + dy * dy) * _straightCost;
    }

    private double diagonal(Node node) {
	float dx = Math.abs(node.x - _endNode.x);
	float dy = Math.abs(node.y - _endNode.y);
	float diag = Math.min(dx, dy);
	float straight = dx + dy;
	return _diagCost * diag + _straightCost * (straight - 2 * diag);
    }

    // public float getVisited() {
    // return ArrayUtils.addAll(_closed, _open);
    // }
}

2503/100

Android-android:configChanges

这是hipak那边测试反馈回来的一个问题,说来惭愧,一直没注意到这个问题的存在。以为Power键就是onPause处理就完了,结果不是。
这里边google的设计或许也有点问题,在竖屏情况下也许是一样处理的,不过当你的app是横屏,那就要注意了。
每次Power键的时候,app是会强制回到竖屏状态的,并且会重新调用Activity的onCreate(),当然很多时候这不是我们想要的。所以就需要用到android:configChanges了,在配置文件里设置android:configChanges="keyboardHidden|orientation",这样在屏幕方向改变的时候就不会重新调用Activity的onCreate(),而是调用onConfigurationChanged(),然后在Activity里重载下

@Override
public void onConfigurationChanged(Configuration newConfig){
	super.onConfigurationChanged(newConfig);
	if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){
    	//横向
  	}else{
       //竖向
	}
}

一般就这么处理下就可以了,要命的是用到了SurfaceView,而SurfaceView和Thread的生命周期是不一样的,唉,这里要说一下Google提供的sample了,里边有bug!!
由于每次Power键的时候会调用SurfaceView的surfaceDestroyed(SurfaceHolder holder),但是回到app的时候又没有执行surfaceCreated(SurfaceHolder holder),于是就咯屁了~~
目前想到一个能解决的方案是在onConfigurationChanged(Configuration newConfig)里手动处理,surfaceDestroyed(SurfaceHolder holder)+urfaceCreated(SurfaceHolder holder)+pause()处理。。。
唉,希望可以找到一个比较好的解决方案吧。。

2602/100

Android-用HttpClient抓取html页面内容

用的类库为commons-httpclient-3.1.jar.有兴趣的下载去。代码如下:

private String getHtmlContent(final String url) {
		String result = "";// 返回的结果
		StringBuffer resultBuffer = new StringBuffer();
		// 构造HttpClient的实例
		HttpClient httpClient = new HttpClient();
		// 创建GET方法的实例
		GetMethod getMethod = new GetMethod(url);
		// 使用系统提供的默认的恢复策略
		getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
				new DefaultHttpMethodRetryHandler());
		// getMethod.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET,"GB2312");
		getMethod.getParams().setContentCharset("GB2312");
		try {
			// 执行getMethod
			int statusCode = httpClient.executeMethod(getMethod);
			if (statusCode != HttpStatus.SC_OK) {
				System.err.println("Method failed: "
						+ getMethod.getStatusLine());
			}
			// 流式读取
			// 读取内容
			// byte[] responseBody = getMethod.getResponseBody();
			// 处理内容
			// String result = new String(responseBody,"GBK");
			// result = getMethod.getResponseBodyAsString();
			// System.out.println(result);
			// System.out.println(getMethod.getResponseCharSet());
			// 推荐做法
			BufferedReader in = new BufferedReader(new InputStreamReader(
					getMethod.getResponseBodyAsStream(), getMethod
							.getResponseCharSet()));
			String inputLine = null;
			while ((inputLine = in.readLine()) != null) {
				resultBuffer.append(inputLine);
				resultBuffer.append("\n");
			}
			result = new String(resultBuffer);
			return result;
		} catch (HttpException e) {
			// 发生致命的异常,可能是协议不对或者返回的内容有问题
			System.out.println("Please check your provided http address!");
			e.printStackTrace();
		} catch (IOException e) {
			// 发生网络异常
			e.printStackTrace();
		} finally {
			// 释放连接
			getMethod.releaseConnection();
		}
		return result;
	}
Tagged as: No Comments
2202/100

Android-ListView简单用法

在Android开发中经常会需要用的列表,你可以用ListActivity,或者ListView,甚至其他方法。
用ListView相对来说更灵活。下边是ListView简单实现代码:
显示java文件:

package org.nwhy.aGirlGallery;

import java.util.ArrayList;
import java.util.HashMap;

import android.app.Activity;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnCreateContextMenuListener;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.AdapterView.OnItemClickListener;

public class aGirlGallery extends Activity {
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		// 绑定Layout里面的ListView
		ListView list = (ListView) findViewById(R.id.lv);

		// 生成动态数组,加入数据
		ArrayList<hashmap <String, Object>> listItem = new ArrayList</hashmap><hashmap <String, Object>>();
		for (int i = 0; i < 10; i++) {
			HashMap<String, Object> map = new HashMap<string , Object>();
			map.put("ItemImage", R.drawable.icon);// 图像资源的ID
			map.put("ItemTitle", "Level " + i);
			listItem.add(map);
		}
		// 生成适配器的Item和动态数组对应的元素
		SimpleAdapter listItemAdapter = new SimpleAdapter(this, listItem,// 数据源
				R.layout.list_items,// ListItem的XML实现
				// 动态数组与ImageItem对应的子项
				new String[] { "ItemImage", "ItemTitle" },
				// list_items中对应的的ImageView和TextView
				new int[] { R.id.ItemImage, R.id.ItemTitle });

		// 绑定数据源
		list.setAdapter(listItemAdapter);

		// 点击事件
		list.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView< ?> arg0, View arg1, int position,
					long id) {
				//do something?
			}
		});

		// 长按事件
		list.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {

			@Override
			public void onCreateContextMenu(ContextMenu menu, View v,
					ContextMenuInfo menuInfo) {
				//do something?
			}
		});
	}

	// 长按菜单响应函数
	@Override
	public boolean onContextItemSelected(MenuItem item) {
		//do something?
		return super.onContextItemSelected(item);
	}
}

2102/100

Flex 4 List Scrolling on Android with Flash Player 10.1

Learned from http://www.jamesward.com/2010/02/19/flex-4-list-scrolling-on-android-with-flash-player-10-1/

One of the challenges of running existing web content on mobile devices is that user interactions differ between mediums. For instance, on a normal computer with a mouse, scrolling though lists is often done by clicking on scroll bars or mouse wheels. On mobile devices that lack a pointing device this is not the best interaction paradigm. On devices with touch screens the paradigm for scrolling is usually a swipe gesture.

In Flash Player 10.1 there are APIs for gestures and multitouch events. I thought it would be fun to hook up the list scrolling on a Flex 4 List to the TouchEvent on my Nexus One. Check out the video:

If you want to see how I created this simple demo, check out the source code. Let me know if you have any questions.
---------------------------------------------------------------------------------------------------------------------
视频很卡,只是随便看了下。看源代码的情况,是一个twitter的list列表展示。
看起来,Flash Player在Android下边运行的不错,希望赶紧出个可以直接发布成APK的Flash IDE吧。
不过真的要是发布了,那也是个头疼的事儿,到底是用Flash开发呢还是用Eclipse开发?
Flash的效率会是如何?对硬件的支持呢?慢慢等吧……只有尝试了才知道。

502/108

Android-How to create an option menu

This post learned from http://www.droidnova.com/how-to-create-an-option-menu,427.html,
droidnova.com is very good site about Android dev,.

Today we learn how you can create an option menu for your application.
Lets start with an empty android project. The package name will be com.droidnova.android.howto.optionmenu and the activity will have the name SimpleOptionMenu.

Our activity should now look very familiar to us:

package com.droidnova.android.howto.optionmenu;

import android.app.Activity;
import android.os.Bundle;

public class SimpleOptionMenu extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

First we have to make a new folder in our res/ directory named menu. In this new directory we will create a new xml file named menu.xml.

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/icon"
        android:icon="@drawable/icon" />
    <item android:id="@+id/text"
        android:title="Text" />
    <item android:id="@+id/icontext"
        android:title="Icon and text"
        android:icon="@drawable/icon" />
</menu>
2601/100

Android-MotoDev Shop4Apps

MotoDev Shop4Apps对中国开放,目前豆腐的状态是刚注册了下,具体还没有发布,晚上回去测试。
另外就是我也没下载Moto的Market客户端,里边的Apk介绍希望做的比Google Market好一点,不然,,只能说两个字,杯具。
来几张可爱的图:
motorola
motorola
motorola
很Q,很可爱~

2001/101

Android-Permission V1.0

Android Permission大全出自1.0 SDK中记录着新改变的访问权限许可。程序执行需要读取到安全敏感项必需在androidmanifest.xml中声明相关权限请求,完整列表如下:
PS:在开发中,调用到系统功能的时候,如果程序代码逻辑无错,但是被强行终止多半都是因为权限的原因。

  android.permission.ACCESS_CHECKIN_PROPERTIES允许读写访问"properties"表在checkin数据库中,改值可以修改上传( Allows read/write access to the "properties" table in the checkin database, to change values that get uploaded)

  android.permission.ACCESS_COARSE_LOCATION允许一个程序访问CellID或WiFi热点来获取粗略的位置(Allows an application to access coarse (e.g., Cell-ID, WiFi) location)

  android.permission.ACCESS_FINE_LOCATION允许一个程序访问精良位置(如GPS) (Allows an application to access fine (e.g., GPS) location)

  android.permission.ACCESS_LOCATION_EXTRA_COMMANDS允许应用程序访问额外的位置提供命令(Allows an application to access extra location provider commands)

  android.permission.ACCESS_MOCK_LOCATION允许程序创建模拟位置提供用于测试(Allows an application to create mock location providers for testing)

  android.permission.ACCESS_NETWORK_STATE允许程序访问有关GSM网络信息(Allows applications to access information about networks)

  android.permission.ACCESS_SURFACE_FLINGER允许程序使用SurfaceFlinger底层特性(Allows an application to use SurfaceFlinger's low level features)

  android.permission.ACCESS_WIFI_STATE允许程序访问Wi-Fi网络状态信息(Allows applications to access information about Wi-Fi networks)

  android.permission.ADD_SYSTEM_SERVICE允许程序发布系统级服务(Allows an application to publish system-level services).

  android.permission.BATTERY_STATS允许程序更新手机电池统计信息(Allows an application to update the collected battery statistics)

  android.permission.BLUETOOTH允许程序连接到已配对的蓝牙设备(Allows applications to connect to paired bluetooth devices)

1401/100

Android-OnGestureListener接口

在做应用的时候难免会碰到触摸事件,Android提供了不少事件,只要实现OnGestureListener接口,并且呢,在onTouch方法里写个:

//记得要implements OnTouchListener,OnGestureListener
//public class mGestureDetector extends Activity implements OnTouchListener,OnGestureListener
private GestureDetector mGestureDetector;
@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	// setContentView(R.layout.main);
	View v = new View(this);
	setContentView(v);
        //mGestureDetector是个GestureDetector对象,记得初始化一下。
	mGestureDetector = new GestureDetector(this);
        //另外呢,需要针对onFling方法的监听,需要在监听的View里边加上:
	v.setOnTouchListener(this);
	v.setLongClickable(true);
}
public boolean onTouch(View v, MotionEvent mo) {
	return mGestureDetector.onTouchEvent(mo);
}

另外是OnGestureListener接口必须实现的几个方法,具体要怎么实现大家自个儿对号入座吧。

public boolean onDown(MotionEvent e) {
	return false;
}
public void onLongPress(MotionEvent e) {
}
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
    float distanceY) {
	return false;
}
public void onShowPress(MotionEvent e) {
}
public boolean onSingleTapConfirmed(MotionEvent e) {
	return false;
}
public boolean onSingleTapUp(MotionEvent e) {
	return false;
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
    float velocityY) {
	return true;
}
601/100

Android – AlertDialog,Dialog

丢一个自定义AlertDialog的例子。

AlertDialog.Builder alert = new AlertDialog.Builder(aBrainExploration.this);

alert.setTitle(R.string.label_enterOneName);

// Set an EditText view to get user input
final EditText input = new EditText(aBrainExploration.this);
alert.setView(input);

alert.setPositiveButton("Ok",
        new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog,
                    int whichButton) {
                Appendable value = input.getText();
                // setTitle(value.toString());
            }
        });

alert.setNegativeButton("Cancel",
        new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog,
                    int whichButton) {
                // Canceled.
            }
        });

alert.show();

相对来说有个更轻量级的Dialog类,用法也是差不多~

3012/090

Android-ImageView setAlpha()的问题

不知道大家有没碰到这种情况,使用同一个图片资源做背景的ImageView,使用setAlpha之后,全部使用该图片资源的ImageView都会被影响到,导致这个问题的原因和解决方案如下:http://android-developers.blogspot.com/2009/05/drawable-mutations.html (PS:被和谐,需要爬墙。)
来个例子说明下,我们需要生成10个ImageView,偶数位的ImageView设置alpha,代码如下:

private int res_ico = R.drawable.icon;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    LinearLayout l= (LinearLayout)findViewById(R.id.layout1);
    for(int i=0;i < 10;i++){

        ImageView iv = new ImageView(this);
        iv.setImageResource(res_ico);
        iv.setClickable(false);

        iv.setAdjustViewBounds(true);
        if(i%2==0){
            ico.setAlpha(125);
        }
        l.addView(iv);
    }
}

这样的话就会发现,所有的ImageView的透明度是和最后设置的值一样的,具体原因在上边的网页里有说明,因为大家用的都是一个资源嘛。
那么怎么解决这个问题呢?
方案如下:

private int res_ico = R.drawable.icon;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    LinearLayout l= (LinearLayout)findViewById(R.id.layout1);
    for(int i=0;i < 10;i++){
        Drawable ico = getResources().getDrawable(res_ico);
        ImageView iv = new ImageView(this);
        iv.setBackgroundDrawable(ico);
        iv.setClickable(false);

        iv.setAdjustViewBounds(true);
        if(i%2==0){
            ico.mutate().setAlpha(125);
        }
        l.addView(iv);
    }
}

mutate()方法是让图片资源mutable,内部工作原理应该就是克隆了一份自己。
另外:

Drawable ico = getResources().getDrawable(res_ico);

要放在循环里,放在循环体外的话照样会出问题,囧。

Page 1 of 212