【学习Android NDK开发】native code通过JNI调用Java方法
2017-04-10 15:16
661 查看
转载自:http://www.cnblogs.com/xitang/p/4174619.html
转载自:http://www.cnblogs.com/dyingbleed/archive/2012/10/12/2721781.html
一、简易入门型:
1、建立Android应用
application name: CallJavaMethod
package name: com.example.cjm
main Activity: MainActivity
main Activity layout: activity_main
2、Java实现
打开layout/activity_main.xml布局文件,添加按钮控件,ID为“display_button_activity_main”
新建接口CJMListener,定义接口方法displaymessage
新建类CJM,实现接口CJMListener
定义native public方法displaySomething
为MainActivity类,实现CJMListener,添加CMJ对象域
添加Button对象域,引用在布局文件中定义ID为“display_button_activity_main”的按钮控件
public class MainActivity extends AppCompatActivity implements CJMListener{
private Button mDisplayBtn;
private CJM cjm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDisplayBtn=(Button)findViewById(R.id.display_button);
mDisplayBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
cjm.displaySomething();
}
});
cjm=new CJM(this);
}
@Override
public void displayMessage(String message) {
Toast.makeText(this,message,Toast.LENGTH_SHORT).show();
}
当用户按下按钮,执行CJM对象的displaySomething方法
类CJM的displaySomething方法使用native关键字进行声明,将使用native code实现
实现上,在nativie code中,会回调CJM对象的displayerMessage方法,并传递String类型的消息,用于显示
注意,在CJM类中displayerMessage的实现,由于native code并不是在主线程中执行,所以使用了Android的Handler执行MainActivity的方法
3、C实现
使用javah为CJM的native方法生成头文件(步骤省略……)
新建.c文件,实现该头文件的方法
我们需要在JNI的C代码调用Java代码。实现原理:使用JNI提供的反射借口来反射得到Java方法,进行调用。
JNI关键方法讲解。
1. 在同一个类中,调用其他方法
注意: 看红色的内容,如何获得呢? 这个是函数的签名。函数签名借住命令
javap -p -s(这两个参数一定要加入)来获得,放到第二个参数即可。
注意:
1. 要加入上面的参数 -p -s
2. signature后面有时候带“;”,不要丢掉。 主要要仔细检查
示例:
这样就可以调用DataProvider中的helloFromJava方法了。
2. 上面的方法是调用的返回值为void的java方法。如果想调用其他类型的。JNI中还提供的许多其他返回类型的方法。
3. 如果java中的方法是静态的,就需要调用GetStaticMethodID 和 CallStaticVoidMethod 方法。
4. 如果C调用的Java方法不在一个类中。
分析:JNI提供的方法都有两个参数:(JNIEnv *env , jobject obj)。 env是JNI提供的方法集合。 obj是上线文。下面的例子的obj不是所需要的上下午,所以要重新创建。
5. 提示
为了避免4中的内容,我们尽量让C要调用的Java方法在同一个类中
转载自:http://www.cnblogs.com/dyingbleed/archive/2012/10/12/2721781.html
一、简易入门型:
1、建立Android应用
application name: CallJavaMethod
package name: com.example.cjm
main Activity: MainActivity
main Activity layout: activity_main
2、Java实现
打开layout/activity_main.xml布局文件,添加按钮控件,ID为“display_button_activity_main”
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:id="@+id/display_button_activity_main" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="Display" tools:context=".MainActivity" /> </RelativeLayout>
新建接口CJMListener,定义接口方法displaymessage
package com.example.cjm; public interface CJMListener { void displayMessage(String message); }
新建类CJM,实现接口CJMListener
定义native public方法displaySomething
package com.example.cjm; import android.os.Handler; public class CJM implements CJMListener { static { System.loadLibrary("cjm"); } private Handler handler; private CJMListener listener; public CJM(CJMListener listener) { handler = new Handler(); this.listener = listener; } @Override public void displayMessage(final String message) { handler.post(new Runnable() { @Override public void run() { listener.displayMessage(message); } }); } public native void displaySomething(); }
为MainActivity类,实现CJMListener,添加CMJ对象域
添加Button对象域,引用在布局文件中定义ID为“display_button_activity_main”的按钮控件
public class MainActivity extends AppCompatActivity implements CJMListener{
private Button mDisplayBtn;
private CJM cjm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDisplayBtn=(Button)findViewById(R.id.display_button);
mDisplayBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
cjm.displaySomething();
}
});
cjm=new CJM(this);
}
@Override
public void displayMessage(String message) {
Toast.makeText(this,message,Toast.LENGTH_SHORT).show();
}
当用户按下按钮,执行CJM对象的displaySomething方法
类CJM的displaySomething方法使用native关键字进行声明,将使用native code实现
实现上,在nativie code中,会回调CJM对象的displayerMessage方法,并传递String类型的消息,用于显示
注意,在CJM类中displayerMessage的实现,由于native code并不是在主线程中执行,所以使用了Android的Handler执行MainActivity的方法
3、C实现
使用javah为CJM的native方法生成头文件(步骤省略……)
新建.c文件,实现该头文件的方法
#include "com_example_cjm_CJM.h" JNIEXPORT void JNICALL Java_com_example_cjm_CJM_displaySomething (JNIEnv *env, jobject thiz) { jclass ClassCJM = (*env)->FindClass(env, "com/example/cjm/CJM"); jmethodID MethodDisplayMessage = (*env)->GetMethodID(env, ClassCJM, "displayMessage", "(Ljava/lang/String;)V"); jstring value = (*env)->NewStringUTF(env, "Hello World!"); (*env)->CallVoidMethod(env, thiz, MethodDisplayMessage, value); }
二、深入理解
背景需求我们需要在JNI的C代码调用Java代码。实现原理:使用JNI提供的反射借口来反射得到Java方法,进行调用。
JNI关键方法讲解。
1. 在同一个类中,调用其他方法
JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DataProvider_callmethod1 (JNIEnv * env, jobject obj){ //在c代码里面调用java代码里面的方法 // java 反射 //1 . 找到java代码的 class文件 // jclass (*FindClass)(JNIEnv*, const char*); jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider"); if(dpclazz==0){ LOGI("find class error"); return; } LOGI("find class "); //2 寻找class里面的方法 // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); jmethodID method1 = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V"); if(method1==0){ LOGI("find method1 error"); return; } LOGI("find method1 "); //3 .调用这个方法 // void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); (*env)->CallVoidMethod(env,obj,method1); }
注意: 看红色的内容,如何获得呢? 这个是函数的签名。函数签名借住命令
javap -p -s(这两个参数一定要加入)来获得,放到第二个参数即可。
注意:
1. 要加入上面的参数 -p -s
2. signature后面有时候带“;”,不要丢掉。 主要要仔细检查
示例:
void notifyOnStatusReport(int32_t status) { if (curEnv != NULL && curObj != NULL) { jclass clsstring = curEnv->FindClass("com/baidu/tieba/liveSdk/publisher/LiveNativeSender"); jfieldID mUsercommandCallbackEventListnerFieldId = curEnv->GetFieldID(clsstring,"mStatusEventListener","Lcom/baidu/tieba/liveSdk/publisher/OnStatusEventListener;"); jobject mUsercommandCallbackEventListner = curEnv->GetObjectField(curObj,mUsercommandCallbackEventListnerFieldId); jclass onStatusEventListenerClsstring = curEnv->FindClass("com/baidu/tieba/liveSdk/publisher/OnStatusEventListener"); jmethodID onStatusReport = curEnv->GetMethodID(onStatusEventListenerClsstring, "onStatusReport", "(I)V"); curEnv->CallVoidMethod(mUsercommandCallbackEventListner, onStatusReport, status); } }
这样就可以调用DataProvider中的helloFromJava方法了。
2. 上面的方法是调用的返回值为void的java方法。如果想调用其他类型的。JNI中还提供的许多其他返回类型的方法。
jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...); jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list); jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...); jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list); jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...); jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list); jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...); jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list); jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...); jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list); jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...); jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list); jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...); jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list); jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__; jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__; jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__; jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__; jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list); void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
3. 如果java中的方法是静态的,就需要调用GetStaticMethodID 和 CallStaticVoidMethod 方法。
JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DataProvider_callmethod4 (JNIEnv * env, jobject obj){ //1 . 找到java代码的 class文件 // jclass (*FindClass)(JNIEnv*, const char*); jclass dpclazz = (*env)->FindClass(env, b20e "cn/itcast/ndkcallback/DataProvider"); if(dpclazz==0){ LOGI("find class error"); return; } LOGI("find class "); //2 寻找class里面的方法 // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); // 注意 :如果要寻找的方法是静态的方法 那就不能直接去获取methodid //jmethodID method4 = (*env)->GetMethodID(env,dpclazz,"printStaticStr","(Ljava/lang/String;)V"); // jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*); jmethodID method4 = (*env)->GetStaticMethodID(env,dpclazz,"printStaticStr","(Ljava/lang/String;)V"); if(method4==0){ LOGI("find method4 error"); return; } LOGI("find method4 "); //3.调用一个静态的java方法 // void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...); (*env)->CallStaticVoidMethod(env,dpclazz,method4,(*env)->NewStringUTF(env,"static haha in c")); }
4. 如果C调用的Java方法不在一个类中。
分析:JNI提供的方法都有两个参数:(JNIEnv *env , jobject obj)。 env是JNI提供的方法集合。 obj是上线文。下面的例子的obj不是所需要的上下午,所以要重新创建。
//obj DemoActivity JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DemoActivity_call_1dp_1method1 (JNIEnv * env, jobject obj){ //在c代码里面调用java代码里面的方法 // java 反射 //1 . 找到java代码的 class文件 // jclass (*FindClass)(JNIEnv*, const char*); jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider"); if(dpclazz==0){ LOGI("find class error"); return; } LOGI("find class "); //2 寻找class里面的方法 // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); jmethodID method1 = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V"); if(method1==0){ LOGI("find method1 error"); return; } LOGI("find method1 "); //3 .调用这个方法 // void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); // jobject (*NewObject)(JNIEnv*, jclass, jmethodID, ...); // jobject (*AllocObject)(JNIEnv*, jclass); jobject dpobj= (*env)->AllocObject(env,dpclazz); (*env)->CallVoidMethod(env,dpobj,method1); }
5. 提示
为了避免4中的内容,我们尽量让C要调用的Java方法在同一个类中
相关文章推荐
- 【学习Android NDK开发】native code通过JNI调用Java方法
- 【学习Android NDK开发】native code通过JNI调用Java方法
- 【学习Android NDK开发】native code通过JNI调用Java方法
- 【学习Android NDK开发】native code通过JNI调用Java方法
- 【学习Android NDK开发】native code通过JNI调用Java方法
- 【学习Android NDK开发】native code通过JNI调用Java方法
- 【学习Android NDK开发】native code通过JNI调用Java方法
- 【学习Android NDK开发】Java通过JNI调用native方法
- Android NDK(JNI)学习总结一:Java代码中申明native函数-Java调用C函数,并在C函数中访问java类和方法、属性
- Android NDK 开发(三)JNI 调用Java属性和方法
- Android NDK 开发(三)JNI 调用Java属性和方法
- 安卓应用开发通过java调用c++ jni的图文使用方法
- JAVA通过JNI调用本地C语言方法
- Java 中通过jni接口调用native code
- 【iOS-cocos2d-X 游戏开发之十三】cocos2dx通过Jni调用Android的Java层代码(下)
- linux下通过eclipse开发用java调用c程序的方法
- JAVA通过JNI调用本地C语言方法
- Java通过JNI调用C语言的方法
- HAL中通过jni调用java方法的问题
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java