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

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

import android.foo.TheSuperClass;

public class SubClass extends TheSuperClass {
  public SubClass() {
    setImportantProperty(true);
  }
}

我也有这样的C代码

// Some file.c
void setThatImportantJavaProperty() {
  JavaVM *vm = AndroidGetJavaVM(); // This returns a valid JavaVM object
  JNIEnv* env;
  (*vm)->AttachCurrentThread(vm,&env,0);

  jclass theSubClass = (*env)->FindClass(env,"com/example/my/package/SubClass");
  jthrowable exception = (*env)->ExceptionOccurred(env);
  if (exception) {
    (*env)->ExceptionDescribe(env);
    // This gives me: "java.lang.NoClassDefFoundError: [generic]".
    // Also,theSubClass is null,so the next line causes a segfault.
  }
  jmethodID theSubClassConstructor = (*env)->GetMethodID(env,theSubClass,"<init>","()V");
  jobject theSubClassObject = (*env)->NewObject(env,theSubClassConstructor);

  (*env)->DeleteLocalRef(env,theSubClass);
  (*env)->DeleteLocalRef(env,theSubClassConstructor);
  (*env)->DeleteLocalRef(env,theSubClassObject);

  (*vm)->DetachCurrentThread(vm);

}

正如内嵌注释所说,运行这个给我一个“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调用.这样做看起来像下面这样:

package com.example.my.package;

import android.app.NativeActivity;
import android.util.Log;

public class MyNativeActivity extends NativeActivity {
  static {
    System.loadLibrary("my_ndk_lib");  
  }

  private static String TAG = "MyNativeActivity";

  public MyNativeActivity() {
    super();
    Log.v(TAG,"Creating MyNativeActivity");
  }

  public static void MyUsefulJavaFunction() {
    doSomethingAwesome();
  }
}

在你的C库中:

jint JNI_OnLoad(JavaVM* vm,void* reserved)
{
  JNIEnv* env;
  if ((*vm)->GetEnv(vm,(void**) &env,JNI_VERSION_1_6) != JNI_OK)
    return -1;

  globalMyNativeActivityClass = (*env)->NewGlobalRef(env,(*env)->FindClass(env,"com/example/my/package/MyNativeActivity"));

  return JNI_VERSION_1_6;
}

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

// Some file.c
void doSomethingAwesomeInJava() {
  JavaVM *vm = AndroidGetJavaVM(); // This returns a valid JavaVM object
  JNIEnv* env;
  (*vm)->AttachCurrentThread(vm,0);

  jmethodID myUsefulJavaFunction = (*env)->GetStaticMethodID(env,globalMyNativeActivityClass,"MyUsefulJavaFunction","()V");
  (*env)->CallStaticVoidMethod(env,theActivityClass,myUsefulJavaFunction);

  (*env)->DeleteLocalRef(env,myUsefulJavaFunction);

  (*vm)->DetachCurrentThread(vm);
}

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

猜你在找的Android相关文章