要深入理解和体会 JNI, 最好有一个实际应用程序来参考, 下面是 headcall 网络电话的例子,
源代码在这里 http://www.headcall.com/download/jni_phone.zip
该例子演示了 headcall 网络电话的一个终端程序, 为了突出 JNI, 我们略去了复杂(却枯燥无味)的媒体部份. 这里
面有独立程序 ( main() ) 和jni程序, 可以对比它们来理解 JNI 的编写.
还有一些编写 JNI 的新问题,
通常为了做复杂的工作, android 程序应该另开线程, 免得影响 UI 主线程的用户响应. 问题在于, 这个线程在那里
开辟? 在 Java 部份还是在 C 部份? 如果在 C 部份, 新线程与 UI 主线程的通讯, 需要使用 C callback Java code,
那是相当的复杂和低效率. 所以我们选择在 Java 层开辟新线程. 这样, 只存在 Java call C code 的需要, 即通常的
JNI 调用. 绝对要避免使用 C callback Java code, 否则, 万千烦恼等着你.
工作线程不能无限循环, 当没事做时, 使用 pause( ) 等待 socket 信号 ( SIGIO ) 或者时钟信号( SIGALRM ). linux
系统的行为是, 这些信号同时会唤醒 pause( ). 但 android 系统有点不同. 信号有效, 但不会唤醒 pause( ). 所以,
我们在 JNI 中改用等待信号灯 ( semaphore ). 这个在 android 中是可行的.
不能在 Java 层实现线程等待, 那是没有用的. 我们在 Java 层开辟新线程, 该线程的消息循环主体却在 C 层.
还有一个要注意的小问题, 写 cache 文件. android 只允许应用程序在自己的 cache 目录下写文件. 这个目录是
C 层不知道的, 必须由 Java 层传递下去. 在网络电话例子中, 它们是通过 Java 的 login( profile ) 带到 C 层的.
还有一些有关 jni 程序中, Java 参数的处理. 例如 Get...( ) 后一定要 Release...( ) 关于这一点, google 的文档也有
特别强调. 否则, 你会在 android 日志 ddms 中看到一堆警告.
完成了 JNI 接口程序, 你的任务完成了. 剩下的是 Java 代码. 那不是你的事. 做 C 程序员, 你是幸运的. 例如, 在
linux 系统下搞个录音和播放, 那是相当的容易. 效果也不会差. 现在换 Java 来做, 写代码不难, 但效果,,,,,,不好说!
如果要显示视频, 那,,,,,, MediaPlayer ?