月度归档: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编码和调用的整个流程和步骤了,以上是一个非常简单的例程,实际的产品设计中会有更多的一些技巧和设计原则在里面。