如何在Android上加载我自己的Java类?

前端之家收集整理的这篇文章主要介绍了如何在Android上加载我自己的Java类?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试使用 Android NDK来从C中编写一些Java代码.该应用程序是一个NativeActivity应用程序.我必须访问一些仅在Java中可用的功能,并且该功能需要您将其他类子类化,所以我不能直接从C执行调用.因此,我有这样的Java代码
  1. // src/com/example/my/package/SubClass.java
  2. package com.example.my.package;
  3.  
  4. import android.foo.TheSuperClass;
  5.  
  6. public class SubClass extends TheSuperClass {
  7. public SubClass() {
  8. setImportantProperty(true);
  9. }
  10. }

我也有这样的C代码

  1. // Some file.c
  2. void setThatImportantJavaProperty() {
  3. JavaVM *vm = AndroidGetJavaVM(); // This returns a valid JavaVM object
  4. JNIEnv* env;
  5. (*vm)->AttachCurrentThread(vm,&env,0);
  6.  
  7. jclass theSubClass = (*env)->FindClass(env,"com/example/my/package/SubClass");
  8. jthrowable exception = (*env)->ExceptionOccurred(env);
  9. if (exception) {
  10. (*env)->ExceptionDescribe(env);
  11. // This gives me: "java.lang.NoClassDefFoundError: [generic]".
  12. // Also,theSubClass is null,so the next line causes a segfault.
  13. }
  14. jmethodID theSubClassConstructor = (*env)->GetMethodID(env,theSubClass,"<init>","()V");
  15. jobject theSubClassObject = (*env)->NewObject(env,theSubClassConstructor);
  16.  
  17. (*env)->DeleteLocalRef(env,theSubClass);
  18. (*env)->DeleteLocalRef(env,theSubClassConstructor);
  19. (*env)->DeleteLocalRef(env,theSubClassObject);
  20.  
  21. (*vm)->DetachCurrentThread(vm);
  22.  
  23. }

正如内嵌注释所说,运行这个给我一个“java.lang.NoClassDefFoundError:[generic]”错误.当我解压缩我的apk,它会显示我的classes.dex文件,它似乎有我的类.我的猜测是,有一些微妙的我在类路径上失踪,但是我无法解决这个问题.

顺便说一句,我可以从C中对C标准的Android库进行类似的调用,而不会出现问题(在上面的同一个C函数中).具体来说,我测试了调用Log.v,并且正确地打印输出.

看来我发现的所有例子都只显示了如何从C中调用普通的Java库,而不是自己编写的Java库,所以我甚至没有找到一个比较的示例项目.

解决方法

我的问题的微妙,以及为什么由Klaimmore和Winston链接的文档并不能解决这个问题,源自于我正在使用NativeActivity类编写一个应用程序.这意味着从来没有可以使用本地类加载器的Java堆栈.没有JNI_OnLoad调用,没有Java方法调用我的本机函数,没有其他方式(我知道)获取本地ClassLoader对象.不幸的是,绝大多数Android JNI文档根本就不是用NativeActivity编写的.

然而,有一个直接的解决方案,这个问题可以使您的生活更容易使用NativeActivity编写应用程序.简单地在Java中子类化NativeActivity.这允许您从NativeActivity的实例化的开始编写和访问任意的Java代码,同时仍然在C中执行NativeActivity允许的其他任何操作.它还允许您以这些文档中描述的方式从C设置您的JNI调用.这样做看起来像下面这样:

  1. package com.example.my.package;
  2.  
  3. import android.app.NativeActivity;
  4. import android.util.Log;
  5.  
  6. public class MyNativeActivity extends NativeActivity {
  7. static {
  8. System.loadLibrary("my_ndk_lib");
  9. }
  10.  
  11. private static String TAG = "MyNativeActivity";
  12.  
  13. public MyNativeActivity() {
  14. super();
  15. Log.v(TAG,"Creating MyNativeActivity");
  16. }
  17.  
  18. public static void MyUsefulJavaFunction() {
  19. doSomethingAwesome();
  20. }
  21. }

在你的C库中:

  1. jint JNI_OnLoad(JavaVM* vm,void* reserved)
  2. {
  3. JNIEnv* env;
  4. if ((*vm)->GetEnv(vm,(void**) &env,JNI_VERSION_1_6) != JNI_OK)
  5. return -1;
  6.  
  7. globalMyNativeActivityClass = (*env)->NewGlobalRef(env,(*env)->FindClass(env,"com/example/my/package/MyNativeActivity"));
  8.  
  9. return JNI_VERSION_1_6;
  10. }

那么在C的某个时刻,你可以做:

  1. // Some file.c
  2. void doSomethingAwesomeInJava() {
  3. JavaVM *vm = AndroidGetJavaVM(); // This returns a valid JavaVM object
  4. JNIEnv* env;
  5. (*vm)->AttachCurrentThread(vm,0);
  6.  
  7. jmethodID myUsefulJavaFunction = (*env)->GetStaticMethodID(env,globalMyNativeActivityClass,"MyUsefulJavaFunction","()V");
  8. (*env)->CallStaticVoidMethod(env,theActivityClass,myUsefulJavaFunction);
  9.  
  10. (*env)->DeleteLocalRef(env,myUsefulJavaFunction);
  11.  
  12. (*vm)->DetachCurrentThread(vm);
  13. }

那就是我发现使用NativeActivity应用程序并入我自己的新Java类的方式.希望这将对我以外的人有用.

猜你在找的Android相关文章