猪头小队长 on November 30th, 2008

自从HTC与Google发售第一部Android手机G1以来,许多手机厂商和非手机厂商都纷纷表示正在研发Android手机:

华硕计划2009年推Android系统智能手机
中移动谷歌正合作开发中文版Android
华为宣布明年推基于Android的智能手机
NTT DoCoMo将于2009年推出Android手机
华硕2009年将推10款Google手机
MOTO孤注一掷:手机业务命系Android
索爱总裁称正在研究谷歌Android系统
联想Android手机明年上市
三星和LG于2009年第三季度发Android手机

而且最近一些天,也看到一些厂商发布了Android手机:

琦基发布全球首款WM/Android双系统手机
Android系统入主山寨手机zzzPhone上市
山寨版谷歌手机G2月内上市

但是到目前为止,在市面上,除了G1,还没有看到第二款Android手机。

Continue reading about 第二部Android手机到底什么时候能发售?

猪头小队长 on November 30th, 2008

今天随便在淘宝和有啊上闲逛,居然看到了为G1设计的皮套,真是好看,就是价格贵了一些,大概要200多块。
当年看到G1刚一发布的时候,就感叹:这回想为它设计一款保护套装可不像为iPhone设计的那么容易了,毕竟这种侧开的设计为包装套的设计带来很大的难度。但是今天一看:人民群众的智慧真是不可限量啊!而且还有横开、侧开、口袋等好几种。
当目前为止还只看到皮(不管是不是真皮)质的,还没有看到类似于iPhone那样的橡胶质的运动型的保护套。也许不久之后就能看到了。
不过眼馋这个之前,还有一件比较重要的事情:得先弄一部G1玩玩,O^oo^O

Continue reading about HTC G1手机皮套

猪头小队长 on November 29th, 2008

今天,我们来研究一下Intent,没错,就是前面说过的比较难理解的那个东西,希望通过这篇文章之后,你发现前面那句话其实是不对的。
前文中说过,Intent就像Activity之间的双面胶,就字面意思而言:“意图, 意向, 目的”, 基本上可以诠释这个对象的作用。它里面包含的就是一些信息,这些信息能够告诉我们当前发生了什么,以及想要干什么。我觉得和前面的事件驱动中的事件非常 像,不同的是,它不仅仅包含事件,还包含一些数据信息。Intent或者也可以说像一个需求说明一样,说明了当前的事件以及一些数据,接下 来,Android会依据这个Intent的说明,为其找到一个Activity,并把这个Intent交给这个Activity。看起来Intent好 像是征婚广告一样哦,Intent提出自己的一些描述(不同的是,他描述的是自己,而不是描述的别人),然后Android根据这些描述找到何时的 Activity。
Intent有两种,一种是显式Intent,另一种是隐式Intent。显式Intent会在自己的说明中直接声明由谁(哪个Activity)来接收 处理这个Intent。显式的Intent是说,我已经有了意中人了,告诉Android不用费劲找了,可以直接定位到意中人,例如前文中的这个例子:

Intent intent = new Intent();
intent.putExtra("name", editText.getText().toString());
intent.setClass(ActivityLifecycle.this, AlertDialog.class);

通过setClass方法,直接告诉Android,此Intent交由AlertDialog处理。也可以通过setComponent()、setClassName()等方法来做同样的事情。
在一般的程序中, 我觉得使用显式Intent已经足够了。这样程序看起来简单易懂,毕竟大多数的Android程序都不会有太复杂的Activity之间的关系。
在前文中的另外一个方法中,使用的就是隐式的Intent。隐式Intent呢,比较含蓄,比较糊涂,比较模糊,还没有明确的目标,并且比较悲观,不会对对方提一些要求,只是描述了一下自己的情况,意思就是说,我就是我所描述的这样的一个人,谁能接受, 谁就可以应征。:)

Intent intent = new Intent();
intent.putExtra("name", editText.getText().toString());
intent.setAction("com.roiding.sample.action.MAIN");

Intent说明自己的方式有:

action 用来指明执行的动作,比如说ACTION_VIEW, ACTION_EDIT, ACTION_MAIN,这都是在Android中定义的标准action,开发者可以自己定义自己需要的action,用字符串来表示。更多标准 action参看这里。
category 描述action的附加信息,这个属性我一直不太明白,它被设计出来的用意到底是为什么,到目前为止,我对他的理解是:它就像一个action类别,例 如:CATEGORY_LAUNCHER、CATEGORY_ALTERNATIVE。属于CATEGORY_LAUNCHER这个类别的,可以被 Android放到顶级列表(类似于九宫格的那个界面)中被执行,属于CATEGORY_DEFAULT这个类别的,可以用 startActivity(intent)来启动Activity,等等。而这些行为都是Android内定的,所以自定义category不知道会有 什么意义,更多标准category参看这里。
data 动作操作的数据,这部分数据会像嫁妆一样,携带给接收它的Activity,Uri格式。Uri的概念和传统的URI的概念是一致的,遵循RFC 2396。 而Uri最终是由ContentProvider提供的,所以会涉及到ContentProvider的概念,这里也暂时不去解释了,只需要知道这个 data所声明的数据,就像一个url一样,通过这个url,可以找到提供这个url的ContentProvider提供的数据,然后就可以操作这些数据了。这里面的data似乎和前面的extras功能有重叠?按照我的理解,data确实可以放到extras中传递,但是单独把它提出来确有它的用意。在后面的IntentFilter中会有交代。

既然已经比喻为征婚广告了,把Intent比喻为征婚的需求,那么由Android系统根据什么挑选的候选人呢?
前面中说过这个文件:AndroidManifest.xml,而且当时将其比喻为户口簿,这下好了,所有的适龄青年(Activity)都在这个大的户口簿上了,按照Intent的需求直接在户口簿中寻找就可以了。那又是如何知道哪个适龄青年是否符合要求呢?
在AndroidManifest文件中,对每个适龄青年(Activity)都做了说明,就是intent-filter,它说明了当前这个适龄青年愿意接收什么样的需求,这样当Intent与这个Intent-filter中的说明一致时,Intent就找到了Activity。
这样,当一个Intent的所有说明,都被Activity的intent-filter接受时,这个Activity就是候选人之一。如果有多个 Activity成为候选人,那么在程序运行的时候Android提示你从多个Activity中手动选择一个来作为最终的intent接收执行者。
对于Activity来说,在它的intent-filter中,可以有多个action,多个category,多个data,这样可以有多个Intent可以与之匹配。
说到这里,前面的那个关于data和extras功能重叠的问题似乎还没有解决,所以这个data的重要的作用就是,它提供了一种反向挑选的机制,使 Activity对Intent也可以提出要求,要求Intent的data必须是intent-filter中声明的data中之一(因为可以有多个 data)。这点是非常重要的,不然又会出现ActivityNotFoundException之类的错误了。
到此篇文章为止,一般的Android界面编程应该已经够用了,而对于ContentProvider、Adapter、Services等,在一般的应用中,可以完全不用考虑。等到必须要使用的时候再说吧。

Continue reading about 设计Android的用户界面(五)

猪头小队长 on November 24th, 2008

在前面的文章中,已经创建好了一个用户演示Activity生命周期的示例,但是由于那篇文章篇幅过长,所以分成两部分来写,在这篇文章中,将详细介绍Activity的生命周期。
了解Activity的生命周期是非常有必要的,在后面的文章中会涉及到数据的保存(也就是持久化)等功能,而保存时机的选择关乎用户体验,而了解Activity的生命周期会对时机的选择有更好的理解。
在文档中,已经有了比较清晰的说明:

如果一个Activity显示在最前端,它的状态时active或者是running
如果一个Activity失去焦点,但是还能在屏幕上看到它,比如说,被一个非全屏的或者是透明的另一个Activity遮盖,它此时的状态是paused。一个处于paused状态的Activity,保持着所有自身的状态和信息,秉持着与window manager的联系,但是当系统内存不足时,可能会被系统终止
如果一个Activity完全看不见了,被其他的Activity完全挡住,它的状态变成stopped。处于stopped的Activity虽然也保留着如同paused状态一样的特性,但是此时的它更容易被系统终止
如果一个Activity处于paused或者stopped状态时,系统可以通过要求Activity结束或者强制kill的方式从内存中删除这个Activity,当它在此需要显示时,就需要restart和重新加载以前的数据。(可见,适时的保存数据的重要性)

用一个状态装换图来说明问题:

仔细品味这张图,和上面的说明,会很好的理解Activity的生命周期。接下来,用前面的示例程序来具体说明一下。在前面的示例程序中,写了很多空方法,方法中只是打印了一行日志,这些方法都是Activity在进行状态转换的时候要使用的方法。

程序启动
INFO/ActivityLifecycle: onCreate …
INFO/ActivityLifecycle: onStart …
INFO/ActivityLifecycle: onResume …
点击一下第一个按钮,会弹出一个小对话框,主Activity在对话框的后面还是能看的见,此时的Activity的状态时paused
INFO/ActivityLifecycle: onPause …
然后,点击一下模拟器的返回按键,小对话框消失,返回到主Activity
INFO/ActivityLifecycle: onResume …
点击一下第二个按钮,一个新的Activity会代替当前的Activity
INFO/ActivityLifecycle: onPause …
INFO/ActivityLifecycle: onStop …
这时候,主Activity的状态就变成了stopped了
点击一下模拟器的返回按键,返回到主Activity
INFO/ActivityLifecycle: onRestart …
INFO/ActivityLifecycle: onStart …
INFO/ActivityLifecycle: onResume …
再次点击一下模拟器的返回按键,退出程序
INFO/ActivityLifecycle: onPause …
INFO/ActivityLifecycle: onStop …
INFO/ActivityLifecycle: onDestroy …

注意一下第一个按钮和第二个按钮被点击之后,所执行的过程是不同的。然后可以进行各种组合的前进退出,通过观察日志了解Activity的生命周期。

Continue reading about 设计Android的用户界面(四) -2