月度归档:2010年04月

偶像离开了!

刚刚送偶像上的 691,偶像今天就离开了,一个朝夕相处的兄弟就这么走了,再相见已不知会是何年何月了。偶像一路走好,我们都会想你的。

谢谢你偶像,陪我走过这么长的时间!谢谢!

曾几何时,我们抱怨自己没有得到重用,曾几何时,我们羡慕他人创业成功,曾几何时我们看着别人高升眼红。

也许你的今日就是你期待已久的美好未来?一起观摩南美阿根廷带来的一个短剧“El empleo(雇工人生)”。

Andorid 之菜鸟感观

前一阵突然想到玩一玩 Android 这个平台,回想当时还在大学的时候,曾经也下载过 SDK,傻乎乎地折腾了一天,后来因为模拟器的问题无法解决而无果而终了。

如今再次回过头来看看当年那么年轻幼小的 Android 已经成为了庞然大物,众多的硬件厂商,翘首以待的运营商,数不胜数的开发人员 (包括潜在的),让 Android 瞬时间成为了一个红得发烫的东西了。昨天 lenovo 发布了他们的最新款乐 Phone 手机,基于 OMS 开发的操作系统,应该和中移动的 OPhone 隶属于同一分支。刚刚看了 keso 的 联想移得动吗?, 跟我昨天和舍友的一番交流有较多相似之处,两年前以 1 亿美金出售其移动业务的联想,在今日反其昨日之道而行,所谓老马还吃回头草。自然是有他们的理由的,2008 年是山寨手机最为抢手的日子,国内的手机市场中高端由国际手机制造厂商控制,而低端手机的市场被山寨机侵蚀,我们看到了波导的关门,联想的退出,中兴和华为退出品牌市场为他人做嫁衣裳,也许这就是当时联想的原因。而今天,山寨已经逐渐降温,走出国内走向世界了,出口第三世界的国家,山寨在赤道附近形成了的一道美丽的风景线。由 iPhone 主导的智能手机市场已经逐渐形成,国内智能机的消费群体和市场已经形成,但是鉴于咱们国家的诸多政策,iPhone 以及其他优秀的产品很难在国内这个生态中生存,只能借着水货商家的一根根小水管养活了国内一些饥渴症患者。在这个时候,其实国内已经有了一个很好的消费空间和氛围,但是国内暂时没有什么能拿得出手的设备,经常宕机的魅族虽说是国产,但是也不能因为你是亲兄弟的产品就老死机啊。

再次进入市场的联想,选择了一个很好的时机,而且是在中移动推出 OPhone 之后,OMS 的逐渐成熟和衍生,无疑给联想扫清了很多的道路。那么联想选择 Android 这个平台自然也是有它的理由的,当然我想最大的莫过于这个东西不要钱,拿来就能用,如果愿意还可以掏点钱,跟 Google 签订 OEM 的诸多协议,拿到私有分支的代码和 API。关于 Google Androd 开源的两三事,可以参考 最封闭的开源系统,话说 Andorid 的八宗罪

======================================

回到话题,这几日初步研究了一下 Android,根据它的 Tutorials 学习了几个示范程序,然后看了一下 SDK 包中的 Samples 目录下的几个程序,感觉良好。

首先,Android 的开发完全是面向 Java 的,与平台实际没有太多相关性,因为 Google 又一次很聪明的选择了一个已有的强大的平台来推广自己的产品,使用 Linux Kernel+Java+API 机制,几近完美的俘获了大部分开发人员的心,Android 的开发门槛非常之低,你完全可以在你的 PC 上开发,Windows 和 Linux 皆可,如果你再时尚一些,Mac OS 系列也是没有问题的。不像 iPhone 那般,你必须有了小白之后才能开始你的开发,而且你得重新开始学习一门名为 Objective-C 的语言,也许之前你都没有听说过的一门语言。Android 使用 JNI 机制,提供 Java 语法的 API 让诸多 Java 程序员直接成为了 Android underlying developer。而且在金融危机的这一段时间,IT 行业失业现象还是较为严重的,离开了企业的开发者完全可以在自己家中开始自己 SOHO 生活了。

其次,IDE 的友好性,eclipse 的 ADT 插件用起来真的很爽,能解决你绝大部分的问题 (当然现在我还没哟遇到什么很棘手的问题),DDMS Perspective 下强大的 Log 系统,和模拟器完美的结合能让你迅速的定位到问题的所在和异常信息。另外模拟器的高度可定制化,也是不错的,在新建模拟器时可以指定是否模拟 SD Card,Touch-Screen 等等。

第三,文档的丰满。总是感叹别人的产品为何就能做得这么成功,开发人员拿起文档就能直接开始干活了,这就是境界啊!虽然有些文档也存在错误,例如实例中的 NotepadV2 中就有一个明显的错误,关于 Intent 的返回值为 RESULT_OK 明显是错误的,因为调用这个 Intent 对象的 NotepadV2 自己定义了其需要的返回值为 ACTIVITY_CREATE 和 ACTIVITY_EDIT,不过调试一下就能发现问题所在了,孰能无过呢。

最后,让我感觉非常不爽的一点是,我们国家的开发人员申请不了 Dev Phone,杯具啊!

说了这么多,接下来该好好学习了。Android, I’m comming, Hello Android World!

http://blog.donews.com/keso/archive/2010/04/20/1583526.aspx 联想以

漫谈 JNI

引子

我们首先来看一枚业界新闻:

北京时间 4 月 6 日,据国外媒体报道,TIOBE 网站发布了最新的《四月份编程语言排名》,下面让我们一睹为快:

时隔 4 年之后,C 语言荣登本月榜单中位居榜首,近十年来 C 语言的使用率一直稳定在 15%-20% 之间。这一次由于长期霸占第一宝座的 Java 略显颓势,从而给了 C 语言超过的机会。

随着 JVM(Java 虚拟机)可以支持越来越多的语言,Java 的强大势力正在逐渐被瓜分。以 JavaFX 脚本为例,该语言的排名已经迅速蹿升至 22 位。

此外,Objective-C 和谷歌 Go 语言依然是上升势头最明显的编程语言,显示出新语言的旺盛生命力。

TIOBE 开发语言排行榜每月更新一次,依据的指数是基于世界范围内的资深软件工程师和第三方供应商,包括谷歌、微软等巨头公司均参与统计,其结果作为当前业内程序开发语言的流行使用程度的有效指标。

我们看到了 Java 语言生命力的旺盛,特别是在 Java
2 之后的版本,也就是 JDK5(Tiger) 发布之后,Java 语言的应用更是爆炸式的增长,时值互联网飞速成长迅猛发展之际,Java 语言与生俱来的跨平台特性以及良好且可控的安全性成为了互联网技术企业首选的开发语言。借着 Sun 公司当年在服务器市场上强劲的表现,Java 语言顿时成为 TIOBE 排行榜上的新贵。

Java 应用如此成熟与广泛,在 Google.com 上搜索 Java 得到的结果条数是“Results 1 – 10 of about 196,000,000 for  Java”,搜索 C++得到的结果条数是“ Results 1 – 10 of about 53,300,000 for C++
”,那么我们再来看看关于 JNI 的搜索结果“ Results 1 – 10 of about 1,980,000 for Java Native Interface
”和 Java 2D 做一个对比“ Results 1 – 10 of about 2,710,000 for Java 2D”。从这些结果中我们能看出一些东西,Java
Native Interface(JNI) 相较于 Java 中并不常用的 Java 2D API 的关注程度还低,也就是说 JNI 其实跟 Java 主体上的流行半毛钱关系都没有,那么 JNI 为什么要存在呢,JNI 又能给我们带来什么呢?

JNI 带来了什么

Java 语言的成功很大程度上得于 API 的丰富和设计的良好,Java API 为广大开发人员节省了大量的时间提高了开发效率,使得项目的交付更为敏捷。但是 API 注定存在其局限性,那么我们在什么时候需要使用到 JNI 呢?

1.         所开发的应用程序要使用到与平台相关的属性,而 Java 标准类库不支持对这些属性的处理;

2.         已经拥有了用其他编程语言实现的应用程序或库,希望用 Java 直接调用这些实现;

3.         程序的某个模块对运行的时间效率要求很高,从而希望用较低级的语言 (如汇编) 来实现,同时希望在 Java 应用程序中使用这个模块。

从目前市场上对 JNI 应用的案例来看,最为主要的应用场景一般是源于上面的第二点原因,在已有类库的基础上进行开发平台的迁移。近来比较热门的 Android 移动终端 OS 平台就是基于 JNI 技术来实现的,本质上 Android 的核是 Linux 内核的子集,基于该内核使用 Java 平台进行了良好的封装,提供给开发人员一个高可用性的 SDK
Platform。开发人员只需了解 Java 平台的特性,根据 API
Documentation 就完全可以开始编码了,并不需要知道其内部的实现机制,着实是为开发人员谋福利啊,当然此举更是从根本上劫持了诸多原本不属于该开发阵营中的开发人员,任何熟悉 Java 平台开发的开发人员顿时全成为了 Android 平台开发的潜在用户。技术也是可以带来市场的。

这就是 JNI 给我们带来的,借助 Java 语言的跨平台特性,以及开发阵营的强大,各大企业和机构基于已有的类库和程序进行二次封装,不仅能延续产品的持续发展,还能扩大二次开发人员的阵营,而不落于 IT 技术发展的潮流。说了这么多废话,那么如何使用 JNI 技术来进行二次封装呢?

Hello JNI World

1.         编写并编译 Java 代码

使用称手的工具 (IDE) 编写 Java 代码,例如保存在” E:\JavaWorkspace\Laputa\com\laputa\jni\test\HelloJNIWorld.java”

package com.laputa.jni.test

public class HelloJNIWorld{

public native void sayHello();

public static void main(String[] args){

HelloJNIWorld hello = new HelloJNIWorld();

hello.sayHello();

}

}

进入” E:\JavaWorkspace\Laputa\”, 使用命令” javac com\laputa\jni\test\HelloJNIWorld.java”编译该文件,由于未指定编译结果路径,生成的 class 文件将保存在源文件同一目录下,得到”
e:\JavaWorkspace\Laputa\com\laputa\jni\test\HelloJNIWorld.class”。

2.         生成 JNI 头文件

使用 javah 命令生成头文件,”javah –jni com.laputa.jni.test.HelloWorld”,将会生成一个”
e:\JavaWorkspace\Laputa\com_laputa_jni_test_HelloJNIWorld.h”。在生成头文件的时候有两点需要注意,一是”javah –jni”
后面需要写类的全限定名 (自行查阅资料了解全限定名相关知识),并且执行该命令的当前目录下要能找到全限定名中的路径,也就是说执行命令的路径应该在包路径的上一层目录,这里我们将 com.laputa.jni.test 包保存在”E:\JavaWorkspace\Laputa”下,那么我们执行 javah 命令的路径也应该是”
E:\JavaWorkspace\Laputa”; 二是未指定生成头文件的目标目录时,默认将头文件生成在当前目录下。头文件的样式如下:

/* DO NOT EDIT THIS FILE – it is machine generated */

#include <jni.h>

/* Header for class com_laputa_jni_test_HelloJNIWorld */

#ifndef _Included_com_laputa_jni_test_HelloJNIWorld

#define _Included_com_laputa_jni_test_HelloJNIWorld

#ifdef __cplusplus

extern “C” {

#endif

/*

* Class:     com_laputa_jni_test_HelloJNIWorld

* Method:    sayHello

* Signature: ()V

*/

JNIEXPORT void JNICALL Java_com_laputa_jni_test_HelloJNIWorld_sayHello

(JNIEnv *, jobject);

#ifdef __cplusplus

}

#endif

#endif

3.         实现头文件对应的方法

关于 JNI 头文件中的的类型以及相关的内容可以参考 Java Tutorial 中 Java Native
Interface 一章。现在我们就来实现刚才生成的头文件中的 sayHello 方法,至于方法名为何这么长,主要是因为 JNI 就是通过这样的机制来识别方法签名的,开发过程中需要注意的是,对于 Java 文件中的 native 方法最好不要使用重载,因为重载后的 native 方法生成的头文件中的方法将会非常之长,重载的方法名中将会包含其参数信息,例如在 HelloJNIWorld.java 中添加一个 public
native void sayHello(String str); 方法,其生成的头文件中对应方法将会是 (下面标红的文字):

/*

* Class:     com_laputa_jni_test_HelloJNIWorld

* Method:    sayHello

* Signature: (Ljava/lang/String;)V

*/

JNIEXPORT void JNICALL Java_com_laputa_jni_test_HelloJNIWorld_sayHello__Ljava_lang_String_2

(JNIEnv *, jobject, jstring);

这会让我们在查看代码的时候迷惑,所以建议在需要重载的时候直接使用其他的名称,放弃重载为后期维护提供可读性更高的代码。

接下来就可以开始实现我们需要的方法了,例如我的 Java 代码中需要调用 sayHello 这个本地方法,那么我们新建一个对应的 cpp 文件,将方法签名拷贝至 cpp 文件中,实现该方法。

#include “com_laputa_jni_test_HelloJNIWorld.h”

#include <iostream>

using namespace
std;

/*

* Class:     com_laputa_jni_test_HelloJNIWorld

* Method:    sayHello

* Signature: ()V

*/

JNIEXPORT void JNICALL Java_com_laputa_jni_test_HelloJNIWorld_sayHello

(
JNIEnv *, jobject)

{


std::cout << “Hello JNI World” << std::endl;

}

4.         编译链接库并添加至系统 Path 变量中

使用合适的编译器 (VC/GCC) 进行编译和链接,生成合适的链接库 (dll 或者 so 文件)。在编译过程中可能出现头文件包含出现错误的问题,主要是因为在生成的 JNI 头文件中有”#include
<jni.h>”语句,编译器会到系统路径下去查找外部头文件,需要我们在编译的 IDE 或者脚本中指定该文件所在的目录为编译时 Include 路径,另外”jni.h”文件中可能需要使用到与平台相关的一些文件,例如在 Windows 平台下需要使用到”jni_md.h”文件,该文件处于 JDK 安装目录的 include 目录下的 win32 路径下 (其他平台也处于 include 的相应目录下),需要将这个文件所在目录也添加到编译时 Include 路径中,保证编译通过。将该文件加入系统 Path 目录下 (不同的平台使用其特定方式进行添加,在非 Windows 平台下使用 export 命令设置名为 LD_LIBRARY_PATH 的路径参数值为库文件所在目录),以便 Java 程序能加载该库文件 (Java 加载库文件时,需要库文件在系统的 Path 下)。

5.         在 Java 程序中加载库文件,执行代码

在 Java 程序中使用 System.loadLibrary(String libName) 加载系统路径下的库文件 (忽略后缀名)。加载库文件的代码可以使用静态域进行加载,使得类在加载之初就加载库文件,并且之后在当前 JVM 实例中共享使用,不需重复加载库文件。在代码中添加一段代码:

static{

System.loadLibrary(“HelloJNIWorld”);

}

重新编译,执行代码,程序将在控制台输出“Hello JNI World”

以上就是 HelloWorld 的整个编码过程了,流程如下:

  1. 编写 Java 代码,声明本地方法|
  2. 生成 JNI 头文件|
  3. 根据头文件编写 JNI 实现代码
  4. 编译工程,生成链接库
  5. 执行程序,加载链接库,查看结果

这就是 JNI 编码和调用的整个流程和步骤了,以上是一个非常简单的例程,实际的产品设计中会有更多的一些技巧和设计原则在里面。