当前位置: 代码迷 >> Android >> JNI调用java方法解决方案
  详细解决方案

JNI调用java方法解决方案

热度:12   发布时间:2016-04-27 23:02:24.0
JNI调用java方法
java文件中我定义了一个方法CallBack_Msg.在C中调用.


package com.javajnicallback;
....
public class MainActivity extends ActionBarActivity
{
   public static void CallBack_Msg(String msg)
  {
    tv1.setText(msg);
  }
}


C中是这样的

static JavaVM* gJavaVM;
//gJavaVM 通过AndroidRuntime::getRuntime获取到了.

int GetJNIEnv(JNIEnv** pEnv)
{
  jint result=0;
  JavaVMAttachArgs args={0};

  result=(*gJavaVM)->GetEnv(gJavaVM,(void**)pEnv,JNI_VERSION_1_4);
  if(result == JNI_EDETACHED)
  {
    result = (*gJavaVM)->AttachCurrentThread(gJavaVM,pEnv,NULL);
    if (result != JNI_OK)
    {
      log("NOTE: attach of thread failed\n");
      return JNI_ERR;
    }
    return 1;
  }
  else
  if (result != JNI_OK)
    return JNI_OK;
  else
    return JNI_ERR;
}

void __attribute__ ((constructor)) my_init(void);
void my_init(void)
{
  //获取JNIEnv对象
  JNIEnv *env = 0;
  int ndeatch=GetJNIEnv(&env);

  if(env)
  {
    //查找类 package com.javajnicallback;
    jclass javajnicallback;
    jmethodID CallBack_Msg;
    javajnicallback = (*env)->FindClass(env,"com/javajnicallback/MainActivity");
    if(javajnicallback)
    {
      //  public void CallBack_Msg(String msg)
      CallBack_Msg  = (*env)->GetStaticMethodID(env, javajnicallback,"CallBack_Msg","(Ljava/lang/String;)V");
      log("CallBack_Msg:%x" ,(unsigned int)CallBack_Msg);
    }
  }
}

void
Java_com_javajnicallback_MainActivity_sayhi(JNIEnv* env
          ,jobject thiz)
{
  //查找类 package com.javajnicallback;
  jclass javajnicallback;
  jmethodID CallBack_Msg;
  javajnicallback = (*env)->FindClass(env,"com/javajnicallback/MainActivity");
  if(javajnicallback)
  {
    //  public void CallBack_Msg(String msg)
    CallBack_Msg  = (*env)->GetStaticMethodID(env, javajnicallback,"CallBack_Msg","(Ljava/lang/String;)V");
    log("CallBack_Msg:%x" ,(unsigned int)CallBack_Msg);
  }
}


程序编译完成.
现在问题是 so在加载时my_init中执行
(*env)->FindClass(env,"com/javajnicallback/MainActivity");
会找不到类.
java.lang.NoClassDefFoundError:[generic]

但是Java调用Java_com_javajnicallback_MainActivity_sayhi就能找到类.

请问这要如何解决?

//////////////////////////////////////////////////////////////////////
还有个问题so中从线程中调用java 方法CallBack_Msg
线程代码:

void *thread_fun(void* arg)
{

  //获取JNIEnv对象
  JNIEnv *env = 0;
  int ndeatch=GetJNIEnv(&env);

  //查找类 package com.javajnicallback;
  jclass javajnicallback;
  jmethodID CallBack_Msg;
  javajnicallback = (*env)->FindClass(env,"com/javajnicallback/MainActivity");
  if(javajnicallback)
  {
    CallBack_Msg  = (*env)->GetStaticMethodID(env, javajnicallback,"CallBack_Msg","(Ljava/lang/String;)V");
    log("CallBack_Msg:%x" ,(unsigned int)CallBack_Msg);
  }
  jstring msg=(*env)->NewStringUTF(env, "call back msg.");
  
  //public void CallBack_Msg(String msg)
  //这种情况下.如何传 obj
  (*env)->CallStaticVoidMethod(env, obj,CallBack_Msg,msg);

}


请指点! 
------解决思路----------------------
你不能直接找Activity 自己去实例化这个类,JNI里面找不到环境引用,你可以自己实例化一个类 然后把this引用传过来。
------解决思路----------------------
问题1: env不是主线程的env 不能获取自定义的类,可以在主线程中调用 env->NewGlobalRef(object);创建一个全局引用,供线程调用.这样就能找到自定义的类和方法了。
 问题2:同样 你每次调用Jni方法的时候会传递env和obj过来,obj就是this对象,
如 void RequestAD(JNIEnv* env,jobject object,jstring jstrUrl)  同样你在其他的线程中使用的话调用NewGlobalRef创建全局引用,在不在使用的时候调用env->DeleteGlobalRef删除全局引用,要不然java对象不会释放造成内存泄露。
  相关解决方案