【学习Android NDK开发】native code通过JNI调用Java方法
来源:互联网 发布:4维旋转矩阵 编辑:程序博客网 时间:2024/04/28 23:42
转载自: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”
<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,"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 JNI开发(2)--native方法调用Java方法
- Android NDK学习笔记9-JNI调用Java方法
- Java 中通过jni接口调用native code
- Android Studio Jni开发(二)实现Native调用java方法和Native调用Android API
- Android 通过Jni调用Native
- Android NDK(JNI)学习总结一:Java代码中申明native函数-Java调用C函数,并在C函数中访问java类和方法、属性
- Android-本地方法C调用Java中的方法/NDK-JNI开发实例(六)
- Android NDK- native调用Java
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- android ndk 开发jni调用对象方法,数组参数
- Android NDK 开发(三)JNI 调用Java属性和方法
- #菜鸟之旅#Android Studio开发JNI工程——Native调用Java方法获取IMEI
- Android Studio通过JNI调用NDK程序
- android ndk通过jni调用C++
- Android studio快速取得app的SHA1值
- struts2中constant参数设置
- JavaScript中的变量声明
- git 总结
- 2017年2月大数据精华文章集锦
- 【学习Android NDK开发】native code通过JNI调用Java方法
- tensorflow13《TensorFlow实战Google深度学习框架》笔记-06-02mnist LeNet5卷积神经网络 code
- 安卓加密壳(dexcrypt) , 防止apktool,dex2jar 等工具逆向你的apk,附上下载地址
- 将字符串转换成数字
- npm package.json属性详解
- 建立matlab桌面遇到Error Staring Desktop
- Sum of Consecutive Prime Numbers----暴力水题
- nodeJS 几篇关于jwt的博客链接,空闲时候看看
- Charm Bracelet