我们继续Android JNI开发中的常用代码,第二部分将包含如何在JNI中构造实例化一个Java类以及异常处理的具体方法,有关前一部分的内容可以查看Android JNI实例代码(一) 。
三、在JNI中构造和实例化Java类
view plaincopy to clipboardprint?
public class AndroidJniDemo4{ public static native void constructClass(); //JNI方法 public static void main(String[] args){ AndroidJniDemo4.constructClass(); } } class CwjThread implements Runnable { int nCount = 0 ; public void run(){ try{ Thread.sleep(1987); //休眠1987毫秒 }catch(Exception e){ e.printStackTrace(); } System.out.println("Count="+ nCount); } } public class AndroidJniDemo4{ public static native void constructClass(); //JNI方法 public static void main(String[] args){ AndroidJniDemo4.constructClass(); } } class CwjThread implements Runnable { int nCount = 0 ; public void run(){ try{ Thread.sleep(1987); //休眠1987毫秒 }catch(Exception e){ e.printStackTrace(); } System.out.println("Count="+ nCount); } } JNI代码:
view plaincopy to clipboardprint?
JNIEXPORT void JNICALL Java_AndroidJniDemo4_constructClass(JNIEnv *env, jclass clazz){ jclass jclazz , cwjclazz; jmethodID mid , mid2 , runmid ; jobject obj , obj2 ; jclazz = (*env)->FindClass(env, "CwjThread"); //查找Java层的类 if (jclazz == NULL) { return ; } mid = (*env)->GetMethodID(env, jclazz,"<init>", "()V"); //构造CwjThread类 if (mid == NULL) { return ; } obj = (*env)->NewObject(env, jclazz, mid, NULL); //创建该类的实例,生成的新对象为obj cwjclazz = (*env)->FindClass(env, "Ljava/lang/Thread;"); ////得到Thread类 if (cwjclazz == NULL) { return ; } mid2 = (*env)->GetMethodID(env, cwjclazz,"<init>", "(Ljava/lang/Runnable;)V"); //获取Runnable方法ID if (mid2 == NULL) { return ; } obj2 = (*env)->NewObject(env, cwjclazz, mid2, obj); //构造Runnable对象 runmid = (*env)->GetMethodID(env, cwjclazz,"start", "()V"); //获取Runable对象的start方法ID if (runmid == NULL) { return ; } (*env)->CallVoidMethod(env, obj2, runmid); //执行start方法在JNI中,来启动线程 (*env)->DeleteLocalRef(env, jclazz); //我们并没有使用NewLocalRef有关本地引用的内容Android123在 Android JNI开发终极篇中将详细讲述 } JNIEXPORT void JNICALL Java_AndroidJniDemo4_constructClass(JNIEnv *env, jclass clazz){ jclass jclazz , cwjclazz; jmethodID mid , mid2 , runmid ; jobject obj , obj2 ; jclazz = (*env)->FindClass(env, "CwjThread"); //查找Java层的类 if (jclazz == NULL) { return ; } mid = (*env)->GetMethodID(env, jclazz,"<init>", "()V"); //构造CwjThread类 if (mid == NULL) { return ; } obj = (*env)->NewObject(env, jclazz, mid, NULL); //创建该类的实例,生成的新对象为obj cwjclazz = (*env)->FindClass(env, "Ljava/lang/Thread;"); ////得到Thread类 if (cwjclazz == NULL) { return ; } mid2 = (*env)->GetMethodID(env, cwjclazz,"<init>", "(Ljava/lang/Runnable;)V"); //获取Runnable方法ID if (mid2 == NULL) { return ; } obj2 = (*env)->NewObject(env, cwjclazz, mid2, obj); //构造Runnable对象 runmid = (*env)->GetMethodID(env, cwjclazz,"start", "()V"); //获取Runable对象的start方法ID if (runmid == NULL) { return ; } (*env)->CallVoidMethod(env, obj2, runmid); //执行start方法在JNI中,来启动线程 (*env)->DeleteLocalRef(env, jclazz); //我们并没有使用NewLocalRef有关本地引用的内容Android123在 Android JNI开发终极篇中将详细讲述 } 上面的代码可能我们发现JNI中构造一个类比Java层麻烦的多,需要先获取ID,测试是否为空,然后编写类方法的构造和类型签名符号,多了很多这样的操作,不过Android开发网提醒大家毕竟JNI中没有类的声明引用,只有动态获取这些方法的ID所以执行效率可能比Java还有所降低,类似Java反射一样的处理机制,希望大家明白这个道理。
四、JNI中的异常处理实例代码
view plaincopy to clipboardprint?
class AndroidJniDemo5 { private native void createException() throws IllegalArgumentException; //JNI中抛出一个参数不合法异常 private void throwException() throws NullPointerException { throw new NullPointerException("Java error, android123 "); //Java中产生一个空指针异常 } public static void main(String args[]) { AndroidJniDemo5 ajd5 = new AndroidJniDemo5(); try { ajd5.createException(); } catch (Exception e) { e.printStackTrace(); } } static { System.loadLibrary("AndroidJniDemo5"); } } class AndroidJniDemo5 { private native void createException() throws IllegalArgumentException; //JNI中抛出一个参数不合法异常 private void throwException() throws NullPointerException { throw new NullPointerException("Java error, android123 "); //Java中产生一个空指针异常 } public static void main(String args[]) { AndroidJniDemo5 ajd5 = new AndroidJniDemo5(); try { ajd5.createException(); } catch (Exception e) { e.printStackTrace(); } } static { System.loadLibrary("AndroidJniDemo5"); } } 下面的JNI中的异常具体代码
view plaincopy to clipboardprint?
JNIEXPORT void JNICALL Java_AndroidJniDemo5_createException(JNIEnv *env, jobject obj) { jthrowable throwable; jclass clazz = (*env)->GetObjectClass(env, obj); jmethodID mid = (*env)->GetMethodID(env, clazz, "throwException", "()V"); //获取Java中的throwException方法ID if (mid == NULL) { return; } (*env)->CallVoidMethod(env, obj, mid); //执行throwException方法 throwable = (*env)->ExceptionOccurred(env); //有异常发生,其实Android123提醒大家还可以使用JNI中的异常检测ExceptionCheck函数来判断 if (throwable) // 如果发生了异常 { jclass newExceptionClazz; (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); newExceptionClazz = (*env)->FindClass(env,"java/lang/IllegalArgumentException"); //实例化一个参数不合法异常 if (newExceptionClazz == NULL) { return; } (*env)->ThrowNew(env, newExceptionClazz, "JNI cwj exception"); //在JNI中抛出异常 } } JNIEXPORT void JNICALL Java_AndroidJniDemo5_createException(JNIEnv *env, jobject obj) { jthrowable throwable; jclass clazz = (*env)->GetObjectClass(env, obj); jmethodID mid = (*env)->GetMethodID(env, clazz, "throwException", "()V"); //获取Java中的throwException方法ID if (mid == NULL) { return; } (*env)->CallVoidMethod(env, obj, mid); //执行throwException方法 throwable = (*env)->ExceptionOccurred(env); //有异常发生,其实Android123提醒大家还可以使用JNI中的异常检测ExceptionCheck函数来判断 if (throwable) // 如果发生了异常 { jclass newExceptionClazz; (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); newExceptionClazz = (*env)->FindClass(env,"java/lang/IllegalArgumentException"); //实例化一个参数不合法异常 if (newExceptionClazz == NULL) { return; } (*env)->ThrowNew(env, newExceptionClazz, "JNI cwj exception"); //在JNI中抛出异常 } } 最后我们可以看到在JNI中处理很多事情确实需要编写很多代码,同时有关类的构造符号什么的,目前的IDE和编译器无法检查,所以Android开发网提醒大家一定要记住Java签名符号的格式和规范,下一次我们给出一些例子,帮助Android NDK初学者快速了解JNI的规则。
|
|