wangkuifeng0 2011-03-16
Android NDK对于我们的作用和基本常识在 Android NDK开发技巧一 中已经讲明了,今天谈论下实战的技巧吧
1. 在JNI中打印Logcat,首先我们需要在cpp文件中加入 #include <android/log.h> 这个头文件,NDK有关android自己的就给我们这个唯一的文件log.h,其他的需要我们自己hack diy来解决。
jstring jlog; //从Java传来需要打印的字符
jbooleanisCopy;
constchar*szLog=(*env)->GetStringUTFChars(env,jlog,&isCopy);//将java的unicode字符转化为utf8字符
__android_log_print(ANDROID_LOG_WARN,“android123-cwj”,"fromndk=%s",szLog);//打印logcat
(*env)->ReleaseStringUTFChars(env,jlog,szLog);//释放内存
}上面这段比较简单,其中使用__android_log_print函数打印Logcat,第一个参数为log的level,在log.h头文件中定义了
ANDROID_LOG_UNKNOWN=0、ANDROID_LOG_DEFAULT,/*onlyforSetMinPriority()*/
ANDROID_LOG_VERBOSE,
ANDROID_LOG_DEBUG,
ANDROID_LOG_INFO,
ANDROID_LOG_WARN,
ANDROID_LOG_ERROR,
ANDROID_LOG_FATAL,
ANDROID_LOG_SILENT等类型,第二个参数为tag标签,第三个为需要打印的字符。整个例子比较简单,但方便了很多调试。
2. Android NDK给我们提供了zlib库的支持,可以通过本地的方法解压缩zip文件。
3. 有关C语言运行库的一些方法,在string.h文件中描述的比较清楚,可以方便的操作字符串 ,比如
extern void* memccpy(void *, const void *, int, size_t);
externvoid*memchr(constvoid*,int,size_t);
externvoid*memrchr(constvoid*,int,size_t);
externintmemcmp(constvoid*,constvoid*,size_t);
externvoid*memcpy(void*,constvoid*,size_t);
externvoid*memmove(void*,constvoid*,size_t);
externvoid*memset(void*,int,size_t);
externvoid*memmem(constvoid*,size_t,constvoid*,size_t);
extern void memswap(void *, void *, size_t);extern char* strchr(const char *, int);extern char* strrchr(const char *, int);
extern size_t strlen(const char *);
externintstrcmp(constchar*,constchar*);
externchar*strcpy(char*,constchar*);
extern char* strcat(char *, const char *);extern intstrcasecmp(const char *, const char *);
externintstrncasecmp(constchar*,constchar*,size_t);
extern char* strdup(const char *);extern char* strstr(const char *, const char *);
externchar*strcasestr(constchar*haystack,constchar*needle);
externchar*strtok(char*,constchar*);
extern char* strtok_r(char *, const char *, char**);extern char* strerror(int);extern intstrerror_r(int errnum, char *buf, size_t n);
extern size_t strnlen(const char *, size_t);
externchar*strncat(char*,constchar*,size_t);
externchar*strndup(constchar*,size_t);
externintstrncmp(constchar*,constchar*,size_t);
extern char* strncpy(char *, const char *, size_t);相信这些肯定比Java效率快上不少,至少有指针用,在处理字符串等方面效率可能是几百倍几千倍的提升。
4. NDK在I/O处理上会更有效率,比如提供了Socket和File的本地读写,在socket.h文件中包含了标准Socket的各种方法,可以处理TCP和UDP报文,这样和C++服务器的互通,通过NDK解决,不用再为Java的类型字节对齐以及编码而烦恼。
__socketcall int socket(int, int, int);
__socketcallintbind(int,conststructsockaddr*,int);
__socketcallintconnect(int,conststructsockaddr*,socklen_t);
__socketcallintlisten(int,int);
__socketcallintaccept(int,structsockaddr*,socklen_t*);
__socketcallintgetsockname(int,structsockaddr*,socklen_t*);
__socketcallintgetpeername(int,structsockaddr*,socklen_t*);
__socketcallintsocketpair(int,int,int,int*);
__socketcallintshutdown(int,int);
__socketcallintsetsockopt(int,int,int,constvoid*,socklen_t);
__socketcallintgetsockopt(int,int,int,void*,socklen_t*);
__socketcallintsendmsg(int,conststructmsghdr*,unsignedint);
__socketcall int recvmsg(int, struct msghdr *, unsigned int);extern ssize_t send(int, const void *, size_t, unsigned int);extern ssize_t recv(int, void *, size_t, unsigned int);
__socketcall ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);__socketcall ssize_t recvfrom(int, void *, size_t, unsigned int, const struct sockaddr *, socklen_t *);
5. 当然了,对于我们开发最爽的还要属OpenGL ES了,在NDK中所有GL的函数,可以在gl.h和glext.h中查找到,最新版本NDK支持最新的OpenGL ES版本,可以方便移植iPhone上的3D游戏了。Android123已经成功将Cube例子用NDK改造运行,确实比Java来的更方便和亲切。
最后还是一句话,对于Java这种解释型语言不爽的Android开发者NDK才是你最明智的选择,如果你有C/C++的基础,可以解决很多开源项目的移植工作,实现高级的功能,将Java程序员甩在脑后面,开发出色的UI,完全可以拍拖View的舒服,让OpenGL来写常规应用相信更有竞争力。