I am honored to be with you today at your commencement from one of the finest universities in the world. I never graduated from college. Truth be told, this is the closest I’ve ever gotten to a college graduation. Today I want to tell you three stories from my life. That’s it. No big deal. Just three stories.
The first story is about connecting the dots.
I dropped out of Reed College after the first 6 months, but then stayed around as a drop-in for another 18 months or so before I really quit. So why did I drop out?
It started before I was born. My biological mother was a young, unwed college graduate student, and she decided to put me up for adoption. She felt very strongly that I should be adopted by college graduates, so everything was all set for me to be adopted at birth by a lawyer and his wife. Except that when I popped out they decided at the last minute that they really wanted a girl. So my parents, who were on a waiting list, got a call in the middle of the night asking: “We have an unexpected baby boy; do you want him?” They said: “Of course.” My biological mother later found out that my mother had never graduated from college and that my father had never graduated from high school. She refused to sign the final adoption papers. She only relented a few months later when my parents promised that I would someday go to college.
And 17 years later I did go to college. But I naively chose a college that was almost as expensive as Stanford, and all of my working-class parents’ savings were being spent on my college tuition. After six months, I couldn’t see the value in it. I had no idea what I wanted to do with my life and no idea how college was going to help me figure it out. And here I was spending all of the money my parents had saved their entire life. So I decided to drop out and trust that it would all work out OK. It was pretty scary at the time, but looking back it was one of the best decisions I ever made. The minute I dropped out I could stop taking the required classes that didn’t interest me, and begin dropping in on the ones that looked interesting.
It wasn’t all romantic. I didn’t have a dorm room, so I slept on the floor in friends’ rooms, I returned coke bottles for the 5¢ deposits to buy food with, and I would walk the 7 miles across town every Sunday night to get one good meal a week at the Hare Krishna temple. I loved it. And much of what I stumbled into by following my curiosity and intuition turned out to be priceless later on. Let me give you one example:
Reed College at that time offered perhaps the best calligraphy instruction in the country. Throughout the campus every poster, every label on every drawer, was beautifully hand calligraphed. Because I had dropped out and didn’t have to take the normal classes, I decided to take a calligraphy class to learn how to do this. I learned about serif and san serif typefaces, about varying the amount of space between different letter combinations, about what makes great typography great. It was beautiful, historical, artistically subtle in a way that science can’t capture, and I found it fascinating.
None of this had even a hope of any practical application in my life. But ten years later, when we were designing the first Macintosh computer, it all came back to me. And we designed it all into the Mac. It was the first computer with beautiful typography. If I had never dropped in on that single course in college, the Mac would have never had multiple typefaces or proportionally spaced fonts. And since Windows just copied the Mac, it’s likely that no personal computer would have them. If I had never dropped out, I would have never dropped in on this calligraphy class, and personal computers might not have the wonderful typography that they do. Of course it was impossible to connect the dots looking forward when I was in college. But it was very, very clear looking backwards ten years later.
Again, you can’t connect the dots looking forward; you can only connect them looking backwards. So you have to trust that the dots will somehow connect in your future. You have to trust in something — your gut, destiny, life, karma, whatever. This approach has never let me down, and it has made all the difference in my life.
My second story is about love and loss.
I was lucky — I found what I loved to do early in life. Woz and I started Apple in my parents garage when I was 20. We worked hard, and in 10 years Apple had grown from just the two of us in a garage into a $2 billion company with over 4000 employees. We had just released our finest creation — the Macintosh — a year earlier, and I had just turned 30. And then I got fired. How can you get fired from a company you started? Well, as Apple grew we hired someone who I thought was very talented to run the company with me, and for the first year or so things went well. But then our visions of the future began to diverge and eventually we had a falling out. When we did, our Board of Directors sided with him. So at 30 I was out. And very publicly out. What had been the focus of my entire adult life was gone, and it was devastating.
I really didn’t know what to do for a few months. I felt that I had let the previous generation of entrepreneurs down – that I had dropped the baton as it was being passed to me. I met with David Packard and Bob Noyce and tried to apologize for screwing up so badly. I was a very public failure, and I even thought about running away from the valley. But something slowly began to dawn on me — I still loved what I did. The turn of events at Apple had not changed that one bit. I had been rejected, but I was still in love. And so I decided to start over.
I didn’t see it then, but it turned out that getting fired from Apple was the best thing that could have ever happened to me. The heaviness of being successful was replaced by the lightness of being a beginner again, less sure about everything. It freed me to enter one of the most creative periods of my life.
During the next five years, I started a company named NeXT, another company named Pixar, and fell in love with an amazing woman who would become my wife. Pixar went on to create the worlds first computer animated feature film, Toy Story, and is now the most successful animation studio in the world. In a remarkable turn of events, Apple bought NeXT, I returned to Apple, and the technology we developed at NeXT is at the heart of Apple’s current renaissance. And Laurene and I have a wonderful family together.
I’m pretty sure none of this would have happened if I hadn’t been fired from Apple. It was awful tasting medicine, but I guess the patient needed it. Sometimes life hits you in the head with a brick. Don’t lose faith. I’m convinced that the only thing that kept me going was that I loved what I did. You’ve got to find what you love. And that is as true for your work as it is for your lovers. Your work is going to fill a large part of your life, and the only way to be truly satisfied is to do what you believe is great work. And the only way to do great work is to love what you do. If you haven’t found it yet, keep looking. Don’t settle. As with all matters of the heart, you’ll know when you find it. And, like any great relationship, it just gets better and better as the years roll on. So keep looking until you find it. Don’t settle.
My third story is about death.
When I was 17, I read a quote that went something like: “If you live each day as if it was your last, someday you’ll most certainly be right.” It made an impression on me, and since then, for the past 33 years, I have looked in the mirror every morning and asked myself: “If today were the last day of my life, would I want to do what I am about to do today?” And whenever the answer has been “No” for too many days in a row, I know I need to change something.
Remembering that I’ll be dead soon is the most important tool I’ve ever encountered to help me make the big choices in life. Because almost everything — all external expectations, all pride, all fear of embarrassment or failure – these things just fall away in the face of death, leaving only what is truly important. Remembering that you are going to die is the best way I know to avoid the trap of thinking you have something to lose. You are already naked. There is no reason not to follow your heart.
About a year ago I was diagnosed with cancer. I had a scan at 7:30 in the morning, and it clearly showed a tumor on my pancreas. I didn’t even know what a pancreas was. The doctors told me this was almost certainly a type of cancer that is incurable, and that I should expect to live no longer than three to six months. My doctor advised me to go home and get my affairs in order, which is doctor’s code for prepare to die. It means to try to tell your kids everything you thought you’d have the next 10 years to tell them in just a few months. It means to make sure everything is buttoned up so that it will be as easy as possible for your family. It means to say your goodbyes.
I lived with that diagnosis all day. Later that evening I had a biopsy, where they stuck an endoscope down my throat, through my stomach and into my intestines, put a needle into my pancreas and got a few cells from the tumor. I was sedated, but my wife, who was there, told me that when they viewed the cells under a microscope the doctors started crying because it turned out to be a very rare form of pancreatic cancer that is curable with surgery. I had the surgery and I’m fine now.
This was the closest I’ve been to facing death, and I hope it’s the closest I get for a few more decades. Having lived through it, I can now say this to you with a bit more certainty than when death was a useful but purely intellectual concept:
No one wants to die. Even people who want to go to heaven don’t want to die to get there. And yet death is the destination we all share. No one has ever escaped it. And that is as it should be, because Death is very likely the single best invention of Life. It is Life’s change agent. It clears out the old to make way for the new. Right now the new is you, but someday not too long from now, you will gradually become the old and be cleared away. Sorry to be so dramatic, but it is quite true.
Your time is limited, so don’t waste it living someone else’s life. Don’t be trapped by dogma — which is living with the results of other people’s thinking. Don’t let the noise of others’ opinions drown out your own inner voice. And most important, have the courage to follow your heart and intuition. They somehow already know what you truly want to become. Everything else is secondary.
When I was young, there was an amazing publication called The Whole Earth Catalog, which was one of the bibles of my generation. It was created by a fellow named Stewart Brand not far from here in Menlo Park, and he brought it to life with his poetic touch. This was in the late 1960′s, before personal computers and desktop publishing, so it was all made with typewriters, scissors, and polaroid cameras. It was sort of like Google in paperback form, 35 years before Google came along: it was idealistic, and overflowing with neat tools and great notions.
Stewart and his team put out several issues of The Whole Earth Catalog, and then when it had run its course, they put out a final issue. It was the mid-1970s, and I was your age. On the back cover of their final issue was a photograph of an early morning country road, the kind you might find yourself hitchhiking on if you were so adventurous. Beneath it were the words: “Stay Hungry. Stay Foolish.” It was their farewell message as they signed off. Stay Hungry. Stay Foolish. And I have always wished that for myself. And now, as you graduate to begin anew, I wish that for you.
Stay Hungry. Stay Foolish.
Thank you all very much.
音频片段:需要 Adobe Flash Player(9 或以上版本)播放音频片段。 点击这里下载最新版本。您需要开启浏览器的 JavaScript 支持。
目前反编译apk用得比较广泛的有dex2jar+jd-gui组合和apktool。 前者能将Dalvik字节码还原成Java源代码,但还原后的代码在流程方面是很机械的、与人写代码的习惯不一样;后者则完整地将apk的资源文件还原,将代码还原成dex格式(可以理解为Dalvik使用的字节码的源代码)。两者的简单比较如下:
| 工具 | 资源文件 | 代码 | 能否重新打包 | ||
| 能否反编译 | 可读性 | 能否反编译 | 可读性 | ||
| dex2jar+jd-gui | 否 | / | 能 | 较好 | 不能 |
| apktool | 能 | 很好 | 能 | 差 | 能 |
通过比较可以发现,如果想了解应用局部的实现,使用dex2jar就可以了;如果想修改apk的内容,比如汉化、去广告,则必须使用apktool。如果想查看资源文件(如layout),用apktool就可以了——基本能做到百分之百地还原。下面通过示例,比较反编译后代码的复杂度。
示例
示例Android工程仅含一个默认Activity,其中包含onCreate和onClick方法。onClick方法包含一些常用的Java代码结构。代码如下:
package com.appmem.sandbox.dexsample;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import java.io.IOException;
public class DexSampleActivity extends Activity {
private static final String POST_URL = "http://www.appmem.com/post";
private static final String TAG = "DexSampleActivity";
private static final boolean DEBUG = false;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onClick(View v) {
Button button = (Button) v;
String tag = (String) button.getTag();
long current = System.currentTimeMillis();
Log.i(TAG, "Current itme:" + current);
short a = 10;
Log.d(TAG, "Short int:" + a);
int b = a + 30;
Log.d(TAG, "Int:" + b);
char c = 'B';
Log.d(TAG, "char:" + c);
Log.d(TAG, "TAG:" + tag);
if (DEBUG) {
Log.d(TAG, "DEBUG is ON");
}
if (tag != null) {
if ("Haha".equals(tag)) {
Log.i(TAG, "TAG is haha");
} else if ("Shenma".equals(tag)) {
Log.i(TAG, "TAG is shenma");
} else {
Integer tagInt = Integer.parseInt(tag);
switch (tagInt) {
case 0:
Log.d(TAG, "TAG is 0");
break;
case 1:
Log.i(TAG, "TAG is 1");
break;
case 2:
Log.d(TAG, "TAG is 2");
break;
case 3:
Log.i(TAG, "TAG is 3");
break;
}
}
}
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(POST_URL);
try {
client.execute(post);
} catch (IOException e) {
e.printStackTrace();
} finally {
Log.i(TAG, "Here is finally");
}
}
}
使用dex2jar反编译
命令:
dex2jar Demo.apk
dex2jar会将Dalvik字节码转换成JVM字节码,再将JVM字节码还原成Java源代码,最终会生成Demo.apk.jar ,用jd-gui打开后,看到的结果如下:
从截图中可以看到,还原后的代码基本是对人可阅读的——只是代码的结构很奇特。dex2jar能发挥的功能也止步于此。要体现反编译更强大的能力,就要使用apktool。
使用apktool反编译
apktool不仅能够将资源文件还原、将Dalvik字节码转换成smali(一种接近汇编的语言)代码,还能将smali代码重新打包成apk、调试重新打包后的apk。这样就为修改apk提供了可能。命令:
apktool d Demo.apk apk-dex
可以将Demo.apk反编译,并将内容输出到apk-dex(运行前目录apk-dex必须不存在)。apk-dex目录的内容基本保持了Android工程的目录结构:
├── AndroidManifest.xml
├── apktool.yml
├── res
│ ├── drawable-hdpi
│ ├── drawable-ldpi
│ ├── drawable-mdpi
│ ├── layout
│ └── values
└── smali
└── com
其中smali/目录对应Android工程中的src/,因为其中包含的是smali代码。res/目录下的资源文件也被完全还原了。下面让我们来围观一下smali代码:
package com.appmem.sandbox.dexsample; class DexSampleActivity {/*
.class public Lcom/appmem/sandbox/dexsample/DexSampleActivity;
.super Landroid/app/Activity;
.source "DexSampleActivity.java"
# static fields
.field private static final DEBUG:Z = false
.field private static final POST_URL:Ljava/lang/String; = "http://www.appmem.com/post"
.field private static final TAG:Ljava/lang/String; = "DexSampleActivity"
# direct methods
.method public constructor ()V
.locals 0
.prologue
.line 16
invoke-direct {p0}, Landroid/app/Activity;->()V
#p0=(Reference);
return-void
.end method
# virtual methods
.method public onClick(Landroid/view/View;)V
.locals 10
.parameter "v"
.prologue
.line 34
move-object v0, p1
#v0=(Reference);
check-cast v0, Landroid/widget/Button;
move-object v1, v0
.line 36
.local v1, button:Landroid/widget/Button;
#v1=(Reference);
invoke-virtual {v1}, Landroid/widget/Button;->getTag()Ljava/lang/Object;
move-result-object v5
#v5=(Reference);
check-cast v5, Ljava/lang/String;
.line 38
.local v5, tag:Ljava/lang/String;
const-string v7, "DexSampleActivity"
#v7=(Reference);
new-instance v8, Ljava/lang/StringBuilder;
#v8=(UninitRef);
invoke-direct {v8}, Ljava/lang/StringBuilder;->()V
#v8=(Reference);
const-string v9, "TAG:"
#v9=(Reference);
invoke-virtual {v8, v9}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v8
invoke-virtual {v8, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v8
invoke-virtual {v8}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v8
invoke-static {v7, v8}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 44
if-eqz v5, :cond_0
.line 45
const-string v7, "Haha"
invoke-virtual {v7, v5}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v7
#v7=(Boolean);
if-eqz v7, :cond_1
.line 46
const-string v7, "DexSampleActivity"
#v7=(Reference);
const-string v8, "TAG is haha"
invoke-static {v7, v8}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 69
:cond_0
:goto_0
#v6=(Conflicted);v7=(Conflicted);
new-instance v2, Lorg/apache/http/impl/client/DefaultHttpClient;
#v2=(UninitRef);
invoke-direct {v2}, Lorg/apache/http/impl/client/DefaultHttpClient;->()V
.line 70
.local v2, client:Lorg/apache/http/client/HttpClient;
#v2=(Reference);
new-instance v4, Lorg/apache/http/client/methods/HttpPost;
#v4=(UninitRef);
const-string v7, "http://www.appmem.com/post"
#v7=(Reference);
invoke-direct {v4, v7}, Lorg/apache/http/client/methods/HttpPost;->(Ljava/lang/String;)V
.line 72
.local v4, post:Lorg/apache/http/client/methods/HttpPost;
:try_start_0
#v4=(Reference);
invoke-interface {v2, v4}, Lorg/apache/http/client/HttpClient;->execute(Lorg/apache/http/client/methods/HttpUriRequest;)Lorg/apache/http/HttpResponse;
:try_end_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0
.catch Ljava/io/IOException; {:try_start_0 .. :try_end_0} :catch_0
.line 76
const-string v7, "DexSampleActivity"
const-string v8, "Here is finally"
invoke-static {v7, v8}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 78
:goto_1
#v3=(Conflicted);
return-void
.line 47
.end local v2 #client:Lorg/apache/http/client/HttpClient;
.end local v4 #post:Lorg/apache/http/client/methods/HttpPost;
:cond_1
#v2=(Uninit);v3=(Uninit);v4=(Uninit);v6=(Uninit);v7=(Boolean);
const-string v7, "Shenma"
#v7=(Reference);
invoke-virtual {v7, v5}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v7
#v7=(Boolean);
if-eqz v7, :cond_2
.line 48
const-string v7, "DexSampleActivity"
#v7=(Reference);
const-string v8, "TAG is shenma"
invoke-static {v7, v8}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
goto :goto_0
.line 50
:cond_2
#v7=(Boolean);
invoke-static {v5}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
move-result v7
#v7=(Integer);
invoke-static {v7}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v6
.line 52
.local v6, tagInt:Ljava/lang/Integer;
#v6=(Reference);
invoke-virtual {v6}, Ljava/lang/Integer;->intValue()I
move-result v7
packed-switch v7, :pswitch_data_0
goto :goto_0
.line 54
:pswitch_0
const-string v7, "DexSampleActivity"
#v7=(Reference);
const-string v8, "TAG is 0"
invoke-static {v7, v8}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
goto :goto_0
.line 57
:pswitch_1
#v7=(Integer);
const-string v7, "DexSampleActivity"
#v7=(Reference);
const-string v8, "TAG is 1"
invoke-static {v7, v8}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
goto :goto_0
.line 60
:pswitch_2
#v7=(Integer);
const-string v7, "DexSampleActivity"
#v7=(Reference);
const-string v8, "TAG is 2"
invoke-static {v7, v8}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
goto :goto_0
.line 63
:pswitch_3
#v7=(Integer);
const-string v7, "DexSampleActivity"
#v7=(Reference);
const-string v8, "TAG is 3"
invoke-static {v7, v8}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
goto :goto_0
.line 73
.end local v6 #tagInt:Ljava/lang/Integer;
.restart local v2 #client:Lorg/apache/http/client/HttpClient;
.restart local v4 #post:Lorg/apache/http/client/methods/HttpPost;
:catch_0
#v2=(Reference);v4=(Reference);v6=(Conflicted);
move-exception v3
.line 74
.local v3, e:Ljava/io/IOException;
:try_start_1
#v3=(Reference);
invoke-virtual {v3}, Ljava/io/IOException;->printStackTrace()V
:try_end_1
.catchall {:try_start_1 .. :try_end_1} :catchall_0
.line 76
const-string v7, "DexSampleActivity"
const-string v8, "Here is finally"
invoke-static {v7, v8}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
goto :goto_1
.end local v3 #e:Ljava/io/IOException;
:catchall_0
#v3=(Conflicted);
move-exception v7
const-string v8, "DexSampleActivity"
const-string v9, "Here is finally"
invoke-static {v8, v9}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
throw v7
...
.end method
.method public onCreate(Landroid/os/Bundle;)V
.locals 1
.parameter "savedInstanceState"
.prologue
.line 29
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
.line 30
const/high16 v0, 0x7f03
#v0=(Integer);
invoke-virtual {p0, v0}, Lcom/appmem/sandbox/dexsample/DexSampleActivity;->setContentView(I)V
.line 31
return-void
.end method
*/}
smali体现了程序在JVM中的执行步骤,包含了比较低级的内存分配、对象转移、条件判断、方法调用。通过它,我们可以分析对同一种功能,不同的Java代码的写法的优劣。
smali代码,或者说dex文件的格式可以到这里下载。
首先,为7.23遇难同胞默哀3分钟。
进入正题:
前几天某人推荐了一款VOIP的应用-- Viber,试用了一下,感觉非常爽。本着好东西大家一起用的原则,在此推荐一下这款应用。
Viber是一款iOS、Android上的VOIP、短消息应用。简单地说,有了它,在联网(WIFI/3G)的情况下,安装了Viber的双方,能够免费地相互打电话、发短消息。虽然类似的应用非常多,但它却是我碰到过的此类应用中最优秀的。总的来说,有以下优点:
- 无 注册过程,上手简单。首次打开Viber时,你需要将你的手机号告诉Viber,Viber服务器会往这个号码发送一条短信或打一个电话,以此验证此号码 为你所有。如果你填的是本机的号码,那么验证的过程将自动进行,不需要你任何干预。验证完成后,你就可以进行打电话、发短信,在Viber中进行这些操作 与一般的操作完全相同。
- 无流氓行为。这里的流氓行为是指在用户不知情的情况下,程序偷偷进行一些消耗用户资费的行为。国内某些 即时通信的应用,安装完成首次打开会自动发一条短信来验证用户身份。这种行为犹如偷鸡摸狗一般,是每一个有良知、有正义感的程序员应该抵制的。Viber 采用的是接收特殊短信或特殊来电的方法来验证用户身份,对用户没有任何损失。
- 自动匹配联系人。如果你的通讯录中有人也安装了Viber,那么在Viber中可以看这些人,与他们进行通信是免费的。

- 交 互体验好。使用Viber发送文本消息的时候,界面会实时地反映消息的发送状态--正在发送、已发送、已接收,让用户可以清楚地知道消息的当前状态。非常 难得的是,消息的发送速度非常快,状态更新非常实时。此外,打电话、发短信的操作与平常无异,减少了用户的学习成本。整个应用的操作非常流畅,不像某些类 似应用,切换界面时会有停顿或卡住。这是Viber的拨号界面:

- 语音质量不错。Viber的服务器虽然在国外,但相比国内的IM中的语音通话,Viber的质量算是不错的了。而且在3G环境下,能达到如此的语音质量更是很不容易。
- 省电。Viber的电量消耗控制得也非常好,比大多数应用都要低。这点也非常难得。
- 无广告。Viber的官网承诺不会在程序中插入广告。这使得应用的用户体验又上了一个层次,使用起来非常舒服。
- 跨平台。Viber目前支持iOS及Android,官网上说很快就会支持Blackberry(Window Phone、Symbian之流又一次被无情地忽略了)。就目前使用情况来看,两种已支持的平台之间的使用完全没有问题。
Viber 作为一款即时通信的应用,免费、使用简单、容易上手、界面友好、功能完整。从产品角度来说,定位明确、设计合理、用户体验好。从技术角度来说,实现质量非 常高。我的感觉是一款难得的让人用得爽的应用。当然,它也存在一些小的缺陷,比如,语音的质量相比Skype还是差一点,这可能也是技术上的局限性所致。 如果打个分的话,应该有9.5分吧。那0.5分扣在那些小缺陷上。
不知不觉,来到北京快两个星期了,到新公司也快有两个星期了,一切还算顺利。
新的环境,一切都有很大不同:住的、吃的,最重要的是身边的人、所做的工作。由于新公司的特殊性,几乎每天11点半才离开公司,这在以前对我来说,绝对是件不可思议的事情,而到了这里,一切也变得自然。新的环境,使我有些过度兴奋。这,不是很好。我应该一如既往地淡定。
每天都在忙碌中渡过,至于成果,似乎没有。一方面,新的环境需要适应;另一方面,新的作息,工作效率不是很高。公司的文化,和原来的截然不同;身边的同事也都比以前年轻--公司本身也很年轻。是好是坏,没有绝对。我只是庆幸,两种环境,我都经历过。
有幸接触了一些“牛人”,也使我相信了一句话“人都是捧出来的”。
总得来说,这是一个能让你牛B的地方。
作为一名程序猿,看到下面的语句我内牛满面。
- char **argv
- int (*daytab)[13]
- int *daytab[13]
- void *comp()
- void (*comp)()
- char (*(*x())[])()
- char (*(*x[3])())[5]
收录一些比较喜欢的字符表情,比起QQ那种图片表情,我更喜欢GTALK这种不支持图片的聊天方式(现在支持了,但我还是关闭),一来输入快速(打字总比选图片方便吧),二来聊天记录看起来比较整洁。表情含义请随便联想。
→_→
=。=
= =
-_-
- -!
@_@
^_^
^ ^
゜_゜
HTML与XHTML虽然只差一个X,实际上它们却有很大不同。之前一直以为可以模糊地对待它们,导致今天写程序时走了不少歪路。为此,又仔细查看了相关规范。
在区分HTML与XHTML之前,先来讲讲XML吧。它们三者之间有着紧密的联系,术语的定义往往被我们混淆。
XML(eXtensible Markup Language),即可扩展标记语言,它的主要作用是作为数据的载体。它是对SGML语言的简化,很多SGML的概念都原封不动地搬了过来,但有些也是有区别的。XML总体来看是树状结构的,如下:
<books>
<book title="Dreams of the Orange Fairy by Andrew Lang" author="Andrew Lang">
<summary>Originally published in 1889,Andrew Lang's classic "Coloured Fairy Books",have now been restored for modern audiences. "</summary>
</book>
<book title="Homer the Helicopter Grand Canyon Adventures!" author="Julie W. Buscher">
<summary>A concoction of love, friendship, joy &
mischievous behavior wrapped in a brightly colored package that is HOMER, a little,
quick-silver-streak helicopter.</summary>
</book>
</books>
上面的books,title等都是“标记”,这些标记的名称和语义都是可以自定义,这就是所谓的“可扩展”。
虽然XML中的标记和它们的含义都是可以自定义,但它作为数据的载体,在某个特定应用中,各个标签的含义和它们之间的结构必须是预先定义好的。否则,XML中存储的数据就变得没有意义。定义标记的名称和结构的就是DTD(Document Type Declaration),它规定了在XML文档中允许出现的标记,这些标记的类型和它们之间的结构。如果把XML比作一种自然语言,DTD就是这种语言的语法。显然,任何一种语言必须要有一定的语法才有意义。由于XML的树状结构,有时候它比关系型数据库更有用。
目前,XML有两种版本,XML1.0(第五版)和XML1.1(第二版)。
对XML有一定了解后,再看看HTML吧。HTML(HyperText Markup Language),即超文本标记语言。早期的大多数网页,都是用HTML编写的,在浏览器中查看页面源代码就可以看到页面的HTML源代码。从名称上看,和XML一样,HTML也有ML(Markup Language),但它没有XML中的X(eXtensible),这就是说HTML是不可扩展的,它的标签库是规定好的。说HTML“超文本”,是因为在HTML允许插入图片、超链接等非文本内容。
物理学家Berners-Lee在1990年首先规范了HTML,并编写了浏览器和服务器端程序。1991后期,Berners-Lee在Internet上首先公开性地描述了HTML—-一种由“HTML标签”组成的文档,并设计了20种元素,组成了最初的、相对简单的HTML。除了“超链接”标签外,其它标签都是从SGML中借鉴过来的—-13种SGML标签依旧保留在HTML4中。Berners-Lee打算将HTML设计成SGML的一种应用,并在1993年中期发布的第一个HTML规范的提案中定义。以后,HTML一直得到发展。从1996年开始,由W3C组织出资维护HTML规范。HTML也在2000年成为国际标准。最新版本的HTML是1999年后期发布的HTML4.01。
而XHTML是由HTML发展而来,作为XML的一个应用,它是一种形式良好的XML语言。
XHTML是Internet革命中的下一步。迁移到XHTML,内容开发人员可以进入XML的世界,享受它带来的好处,同时对它们的内容的向后、向前兼容性充满信心。
XHTML可以被XML解析器解析,但HTML只能被宽松的XML解析器解析。在HTML中,某些标签可以不包含闭标签,如<br>,<hr>,<param>等,而XML要求标签必须成对出现。因此,用XML解析器解析HTML,当遇到上述标签时,往往会报错。HTML不支持其它命名空间,而XHTML则支持。此外,XHTML、HTML、XML三者的MIME类型也不同,如下表:
| MIME类型 | |
| XML | text/xml,application/xml |
| HTML | text/html |
| XHTML | application/xhtml+xml |
从兼容性和编程容易性来说,XHTML比HTML占一定的优势。它们之间虽然有着许多共同点,但程序在处理时必须区别对待,通过识别MIME类型进行分别处理。
Activity和Task
task就好像是能包含很多activity的栈。 默认情况下,一个activity启动另外一个activity时,两个activity是放在同一个task栈中的,第二个activity压入第一个activity所在的task栈。当用户按下返回键时,第二个activity从栈中弹出,第一个activity又在当前屏幕显示。这样,从用户角度来看,这两个activity就好像是属于同一个应用程序的,即使第二个activity是属于另外一个应用程序的。当然,这是指默认情况下。 task栈包含的是activity的对象。如果一个activity有多个实例在运行,那么栈中保存的是每个实例的实体。栈中的activity不会重新排列,只有弹出和压入操作。 一个task中的所有activity都以整体的形式移动。整个task可以被移到前台或后台。打个比方,当前的task包含4个activity–当前activity下面有3个activity。当用户按下HOME键返回到程序启动器(application launcher)后,选择了一个新的应用程序(事实上是一个新的task),当前的task就被转移到后台,新的task中的根activity将被显示在屏幕上。过了一段时间,用户按返回键回到了程序启动器界面,选择了之前运行的程序(之前的task)。那个task,仍然包含着4个activity。当用户再次按下返回键时,屏幕不会显示之前留下的那个activity(之前的task的根activity),而显示当前activity从task栈中移出后栈顶的那个activity。 刚刚描述的行为是默认的activity和task的行为。有很多方法能够改变这种行为。activity和task之间的联系,以及task中的activity的行为可以通过intent中的标记以及在manifest中的<activity>元素的属性控制。其中,主要的Intent标记有:
- FLAG_ACTIVITY_NEW_TASK
- FLAG_ACTIVITY_CLEAR_TOP
- FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
- FLAG_ACTIVITY_SINGLE_TOP
- taskAffinity
- launchMode
- allowTaskReparenting
- clearTaskOnLaunch
- alwaysRetainTaskState
- finishOnTaskLaunch
默认情况下,一个应用程序中的所有activity都有一个affinity–这让它们属性同一个task。然而,每个activity可以通过<activity>中的taskAffinity属性设置单独的affinity。不同应用程序中的activity可以共享同一个affinity,同一个应用程序中的不同activity也可以设置成不同的affinity。affinity属性决定了:启动activity的Intent对象需包含FLAG_ACTIVITY_NEW_TASK标记,activity的allowTaskReparenting被认为是设置成true。
FLAG_ACTIVITY_NEW_TASK标记
当传递给startActivity()的Intent对象包含FLAG_ACTIVITY_NEW_TASK标记时,系统会为需要启动的activity寻找与当前activity不同的task。如果要启动的activity的affinity属性与当前所有的task的affinity属性都不相同,系统会新建一个带那个affinity属性的task,并将要启动的activity压到新建的task栈中;否则将activity压入那个affinity属性相同的栈中。
allowTaskReparenting属性
如果一个activity的allowTaskReparenting属性为true,那么它可以从一个task(TASK1)移到另外一个有相同affinity的task(TASK2)中(TASK2带到前台时)。
如果一个.apk文件从用户角度来看包含了多个“应用程序”,你可能需要对那些activity赋不同的affinity值。
运行模式
activity的launchMode属性可以有四种值:
- “
standard” (默认) - “
singleTop“ - “
singleTask“ - “
singleInstance“
这4种模式可以按4种分类来区分,以下假设位于task1中的activity1启动activity2:
| 模式分类 | 包容activity2的task | 一个activity是否允许有多个实例 | activity是否允许有其它activity共存于一个task | 对于新的intent,是否总是实例化activity对象 |
| standard | 如果不包含FLAG_ACTIVITY_NEW_TASK标记,则activity2放入task1,否则按前面讲述的规则为activity2选择task | 可被多次实例化,同一个task的不同的实例可位于不同的task中,每个task也可包含多个实例 | 允许 | 是的。当接收到新的intent时,总是会生成新的activity对象。 |
| singleTop | 同standard | 同standard | 允许 | 已存在的activity对象,如果位于目标task的栈顶,则该activity被重用,如果它不位于栈顶,则会实例化新的activity对象 |
| singleTask | 将activity2放到task1栈底 | 不能有多个实例。由于该模式下activity总是位于栈顶,所以actvity在同一个设备里至多只有一个实例 | 允许。singleTask模式的activity总是位于栈底位置。目标activity实例已存在时,如果该实例刚好位于task栈顶,则接收intent,否则到来的intent将会被丢弃,但这会导致目标activity所在的task被移到前台。 | |
| singleInstance | 同singleTask | 同singleTask | 不允许与其它activity共存于一个task。如果activity1的运行在该模式下,则activity2一定与activity1位于不同的task |
对于新到的intent,如果是由新创建的activity对象来接收,则用户可以通过返回键回到之前的activity;如果是由已存在的activity来接收,则用户无法通过返回键返回到接收intent之前的状态。
清空栈
当用户长时间离开task(当前task被转移到后台)时,系统会清除task中栈底activity外的所有activity。这样,当用户返回到task时,只留下那个task最初始的activity了。
这是默认的情况,<activity>中有些属性可以改变这种行为。
alwaysRetainTaskState属性
如果栈底activity的这个属性被设置为true,刚刚描述的情况就不会发生。task中的所有activity将被长时间保存。
clearTaskOnLaunch属性
如果栈底activity的这个属性被设置为true,一旦用户离开task,则task栈中的activity将被清空到只剩下栈底activity。这种情况刚好与alwaysRetainTaskState相反。即使用户只是短暂地离开,task也会返回到初始状态(只剩下栈底acitivty)。
finishOnTaskLaunch属性
这个属性与clearTaskOnLaunch相似,但它只对单独的activity操作,而不是整个task。它可以结束任何activity,包括栈底的activity。当它设置为true时,当前的activity只在当前会话期间作为task的一部分存在,当用户退出activity再返回时,它将不存在。
另外还有一种方法能将activity强行从stack中移出。如果intent对象包含FLAG_ACTIVITY_CLEAR_TOP标记,当目标task中已存在与接收该intent对象的activity类型相同的activity实例存在时,所有位于该activity对象上面的activity将被清空,这样接收该intent的activity就位于栈顶,可以响应到来的intent对象。如果目标activity的运行模式为standard,则目标activtiy也会被清空。因为当运行模式为standard时,总会创建新的activity对象来接收到来的intent对象。
FLAG_ACTIVITY_CLEAR_TOP标记常常和FLAG_ACTIVITY_NEW_TASK一起使用。用2个标记可以定位已存在的activity并让它处于可以响应intent的位置。
启动任务(Task)
Intent filter中有”android.intent.action.MAIN” action和”android.intent.category.LAUNCHER” category的activity将被标记为task的入口。带有这两个标记的activity将会显示在应用程序启动器(application launcher)中。
第二个比较重要的点是,用户必须能够离开task并在之后返回。因为这个原因,singleTask和singleInstance这两种运行模式只能应用于含有MAIN和LAUNCHER过滤器的activity。打个比方,如果不包含带MAIN和LAUNCHER过滤器,某个activity运行了一个singleTask模式的activity,初始化了一个新的task,当用户按下HOME键时,那个activity就被主屏幕“挡住”了,用户再也无法返回到那个activity。
类似的情况在FLAG_ACTIVITY_NEW_TASK标记上也会出现。如果这个标记会新建一个task,当用户按下HOME键时,必须有一种方式能够让用户返回到那个activity。有些东西(比如notification manager)总是要求在外部task中启动activity,在传递给startActivity的intent中总是包含FLAG_ACTIVITY_NEW_TASK标记。
对于那种不希望用户离开之后再返回activity的情况,可将finishOnTaskLaunch属性设置为true。
SN :HT99GL901385
IMEI :357988022628400
Part Number :99HHM065-00
Part Description :SKU,HTC,English-WWE,Malaysia,RegionalID Low,UMTS900/2100,Urban Brown,w/o SIM Lock,HERO-C9#ASIA
Customer Name :
Customer Model :
HTC Model :HERO-C9
Error Message :
HTC主机序列号SN 解析,买机必看!
S/N: SSYWWPPZZZZZ
SS: 产地代码 HT、CH 比较常见
SZ 深圳
SH 上海
HT 新竹
CH 武汉
Y: 生产年份的最后一个数字
WW: 生产周:01 ~ 54(09年用新的方法了,月是123456789ABC代表1、2、3、4、5、6、7、8、9、10、11、12月。日是1~9~A~Z(26个字母中不使用到其中的四个‘’IOQU‘’)代表1~9~10~31日)
PP:产品代码
ZZZZZ:序号
你看 SN 就知道是什么时候生产的了,前提是先用 IMEI 查询.
第一、二行的SN 、IMEI,是SN码和串号,无论是原版HTC还是O2、T mobile换壳的翻新机都有,并且应该和手机背后电池仓内标注的对应。
第三行Part Number是部件编号,对应这台机器的出场批次等信息,我的凯撒是07年第13周的(注:此处错误,应该看 SN),就是4月初出厂的。(有了这个就不怕JS忽悠你这台机器的生产时间了!凯撒是07年的机器,最后一批在08年初。JS要是说“全新,2个月前生产的!”那么楼主可以微笑一下,走人……)
第四行Part Description是部件描述,依次是销售商,版本,语言,售往地区,手机型号,研发代号,网络解锁信息。但从这一排可以看出我的机器是SKU销售的,HTC版本的,繁体中文的,销往香港的TyTN II,内部研发代号Kaiser,也就是我们熟悉的凯撒P4550了。(这一部分最重要!定制商是核心信息,JS改不了的,若JS给你一台黑色外壳标着 HTC的凯撒,此处显示的却是O2、Orange、Vodafone、T mobile等欧美运营商,那么显然他想要卖给你的是换壳翻新机!后面的语言就更明显了,只有台湾和香港的机器会是Traditional Chinese—繁体中文,若此处是English或其他根本不认识的语言,那么显然不是对亚太地区销售的版本,楼主小心。当然香港、台湾、新加坡、马来西亚等亚太版也会存在英文版的啦。)
第五行Customer Name是客户名称,这里的客户指的是作为OME厂商的宏达(HTC),它的客户,也就是谁在HTC这里定制的这一款手机。例如一台O2版的凯撒,客户名称就会显示O2,由于我的凯撒是HTC版,故此栏为空白。
第六行Customer Model是客户处型号、代号。例如我们的凯撒,HTC原厂研发代号为kaiser,销售型号TyTN II ,而在HTC的客户—那些国际电信运营商那里销售时会换上其他的名字,例如Orange版叫HTC TyTN II ,Vodafone版叫VPA Compact ,T-Mobile版叫MDA Vario III,AT&T版叫Tilt ,O2版叫Xda Stellar等等,其实这些都是凯撒。不难看出,第五行和第六行只针对被运营商定制了的版本才有描述,也就是说楼主拿到的机器,若是这两行有显示,则 100%肯定不是HTC版的,无论它的外壳多么HTC,只能说JS的手工好。
第七行HTC Model是该产品在原厂HTC的研发代号,我们的凯撒之所以称之为凯撒,正是因为HTC研发这款机器是取了一个“KAISER-P2A”的代号。
第八行可以无视,除非你填信息时同时填入了SN和IMEI,碰巧你填入的这两条时不配对的。
除了借助官网来验明正身外,最基本的还是楼主自己要细心看,例如机身背后VOID贴是否动过,机器味道是不是新机的橡胶香味等等……
从 “首先通过*#06#” 到 “新机的橡胶香味等等……”
关于台湾,香港版本。
在台湾和香港销售的手机分别为台行和港行,但到了大陆就变为台版和港版,但有些 JS 拿山寨来充当台版,所以要小心。台版的键盘有注音(就是白痴们认为是日本字的符号,这是我们中国人用的拼音符号,和小日本无关)和笔画,港版键盘只有笔画。键盘有专门的公司可以改造,要哪个版本都可以做出来。所以非要买 台湾,香港版本 的朋友 上当的几率非常高。
Traditional Chinese,TWN 是台版的特征。
联强国际(Synnex Technology International Corporation)
这个是经常出现的台版机器的定制公司.
Traditional Chinese,HKG 是香港版本的特征。
其实 HTC 的手机中包括 台版和港版 、新加坡、马来西亚、澳大利亚等地区的产品都是亚太版,除了键盘和默认文字的区别外,机器本身一般没区别。
HTC 也有销往其他地区的机器,也标 HTC ,除了意大利的键盘有问题外,其他的机器也都没问题。
有问题的是代工给欧美电信公司的手机,例如 O2 、T-Mobile、沃达芬 等机器,这些机器都是 14 天机,相当于非常新的 2 手。
还有些机器已经停产了,连 14 天机都没有了,只有翻新机了。
台版和港版 其实不一定能买到,大多数 JS ,认为你不会去查 IMEI ,所以就拿 HTC 版来冒充,甚至用 任何版本 通过翻新来做到和台版或港版 的外观一模一样,还不如便宜些买个 HTC 版(相对于欧美版本来说,也不便宜,但很值得,毕竟欧美版本不是 14 天机就是翻新的多)。


近期评论