在Android上如何加载自己的Java类C语言? [英] How do I load my own Java class in C on Android?

查看:123
本文介绍了在Android上如何加载自己的Java类C语言?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图调用某些Java code,我从C写的采用了Android NDK。该应用程序是一个NativeActivity的应用。我访问了一些功能,只是在Java中可用,以及功能要求你继承另一个类,所以我不能做直接从C调用因此,我有Java的code是这样的:

I am trying to call some Java code that I wrote from C using the Android NDK. The application is a NativeActivity application. I have to access some functionality that is only available in Java, and the functionality requires you to subclass another class, so I can't just directly do the calls from C. Thus, I have Java code like this:

// 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 $ C $ç是这样的:

I also have C code like this:

// 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, theSubClass, theSubClassConstructor);

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

  (*vm)->DetachCurrentThread(vm);

}

作为行内评论说,运行这给了我一个java.lang.NoClassDefFoundError的:[通用]的错误。当我解开我的apk文件,它让我看到classes.dex文件,这似乎有我的班了。我的猜测是,有一些细微之处,我没有关于类路径,但我无法来解决这个问题迄今。

As the inline comments say, running this gives me a "java.lang.NoClassDefFoundError: [generic]" error. When I unpack my apk, it shows me the classes.dex file, which appears to have my class in it. My guess is that there is some subtlety that I am missing regarding classpaths, but I am unable to resolve it thus far.

顺便说一句,我可以没有问题作出类似呼吁从C标准的Andr​​oid库(在相同的C函数以上)。具体而言,我测试调用Log.v并且工作和正确打印输出。

Incidentally, I am able to make similar calls to standard Android libraries from C without a problem (in the same C function above). Specifically, I tested calling Log.v and that works and prints the output correctly.

这一切似乎,我只找到示例显示如何调用普通Java库从C,你写你自己没有Java库,所以我还没有找到一个示例项目来比较。

It seems that all the examples that I am finding only show how to call normal Java libraries from C, not Java libraries you have written yourself, so I haven't even found an example project to compare against.

推荐答案

我的问题的细微之处,为什么由Klaimmore和温斯顿链接到文档中并没有完全解决的问题,从我写一个应用程序的事实茎使用NativeActivity的类。这意味着有从未与局部类加载器提供给我一个Java堆栈。没有JNI_OnLoad电话,也没有Java方法调用到我的本地函数,并没有其他的得到阿霍德当地的ClassLoader对象的方式(即我所知道的)。不幸的是,大多数的Andr​​oid JNI文件根本就没有写NativeActivity的一点。

The subtlety of my question, and why the documentation linked to by Klaimmore and Winston does not quite resolve the issue, stems from the fact that I am writing an app using the NativeActivity class. This means that there is never a Java stack with a local class loader available to me. There is no JNI_OnLoad call, there is no Java method calling into my native function, and there is no other way (that I am aware of) of getting ahold of a local ClassLoader object. Unfortunately, most of the Android JNI documentation is simply not written with NativeActivity in mind.

然而,有一个简单的解决这个问题,使用NativeActivity的编写应用程序的时候,可以让你的生活变得更轻松。只需在Java中继承NativeActivity的。这使您可以编写和访问任意的Java $ C $从NativeActivity的的实例化的开始C,同时还做着一切在C中的NativeActivity的允许。它还允许你设置你的JNI从C在这些文件中所描述的方式调用。这样做看起来是这样的:

However, there is a straightforward solution to this problem that can make your life much easier when writing apps using NativeActivity. Simply subclass NativeActivity in Java. This allows you to write and access arbitrary Java code from the beginning of your NativeActivity's instantiation, while still doing everything else in C as NativeActivity allows. It also allows you to set up your JNI calls from C in the manner described in those documents. Doing this looks something like the following:

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库:

And in your C library:

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语言某些时候,你可以这样做:

Then at some point in C, you can do:

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

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

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

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

这就是我发现纳入自己的新的Java类用NativeActivity的应用程序的方式。希望这将是有用的人除了我之外。

And that is the way I found to incorporate my own new Java classes with a NativeActivity app. Hopefully this will be useful to someone besides me.

这篇关于在Android上如何加载自己的Java类C语言?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆