天天看點

Android NDK中C++調用Java的完整例子

Android NDK中C++調用Java時,如果是線上程中調用Java API,則隻能調用Java靜态的API,如果不是線上程中,則既可以調用Java靜态API,也可以調用Java類成員API。

http://android.wooyd.org/JNIExample中有較詳細的調用說明.

下面是各調用的示例代碼:

JAVA 代碼:

package com.myndk;

...

public class simple_test extends Activity {

    ...

    public void PrintNdkLog(String slog) {  // 成員函數, 不可線上程中被調用

        Log.e("NDK", slog);

    }

    public static void PrintNdkLogThread(String slog) {  // 靜态函數, 可在主線中被調用

        Log.e("NDK-THREAD", slog);

    }

}

C++ 代碼:

static JavaVM* g_JavaVM = NULL;

static jobject g_InterfaceObject = 0;

static const char *g_JavaClassName = "com/myndk/simple_test";

static jobject getInstance(JNIEnv *env, jclass obj_class)

{

    jmethodID  c_id = env->GetMethodID(obj_class, "<init>", "()V");

    jobject obj = env->NewObject(obj_class, c_id);

    return obj;

}

static void GetInterfaceObject(JNIEnv *env, const char *path, jobject *objptr)

{

    jclass cls = env->FindClass(path);

    if (!cls)

    {

        return;

    }

    jmethodID constr = env->GetMethodID(cls, "<init>", "()V");

    if (!constr)

    {

        return;

    }

    jobject obj = env->NewObject(cls, constr);

    if (!obj)

    {

        return;

    }

    (*objptr) = env->NewGlobalRef(obj);

}

int JniLoad(JavaVM* jvm, void* reserved)

{

    g_JavaVM = jvm;

    JNIEnv *env;

    if (jvm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK)

    {

        return -1;

    }

    GetInterfaceObject(env, g_JavaClassName, &g_InterfaceObject);

    return JNI_VERSION_1_6;

}

void JniUnLoad(JavaVM* jvm, void* reserved)

{

    JNIEnv *env;

    if (jvm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK)

    {

        return;

    }

    env->DeleteGlobalRef(g_InterfaceObject);

}

void PrintNdkLog(const char *format, ...)

{

    va_list arg_ptr;

    char sLogBuff[1024];

    if (g_JavaVM == NULL)

        return;

    va_start(arg_ptr, format);

    vsprintf(sLogBuff, format, arg_ptr);

    va_end(arg_ptr);

    int status;

    JNIEnv *env = NULL;

    bool isAttached = false;

    status = g_JavaVM->GetEnv((void**) &env, JNI_VERSION_1_6);

    if (status < 0)  //表示PrintNdkLog是線上程中被調用的

   {

        status = g_JavaVM->AttachCurrentThread(&env, NULL);

        if (status < 0)

        {

            return;

        }

        isAttached = true;

    }

    if (isAttached)  // PrintNdkLog線上程中被調用, 調用Java靜态API

    {

        jclass cls = env->GetObjectClass(g_InterfaceObject);

        if (cls != 0)

        {

            jmethodID mid = env->GetStaticMethodID(cls, "PrintNdkLogThread", "(Ljava/lang/String;)V");

            if (mid != 0)

            {

                jstring jstrMSG = env->NewStringUTF(sLogBuff);

                env->CallStaticVoidMethod(cls, mid, jstrMSG);

            }

        }

        g_JavaVM->DetachCurrentThread();

    }

    else  // PrintNdkLog不是線上程中被調用, 調用Java類成員API

    {

        jclass cls = env->FindClass(g_JavaClassName);

        if (cls != 0)

        {

            jobject obj = getInstance(env, cls);

            jmethodID mid = env->GetMethodID(cls, "PrintNdkLog", "(Ljava/lang/String;)V");

            if (mid != 0)

            {

                jstring jstrMSG = env->NewStringUTF(sLogBuff);

                env->CallVoidMethod(obj, mid, jstrMSG);

            }

        }

    }

}