Android JNI 在C中调用Java(包括自定义的Java方法和Log)
2017-04-22 09:00
519 查看
项目简介:
该项目为在C中调用Java的方法详细介绍:
用户点击按钮后,将会弹出一个对话框,但是该对话框不是由Java方法调用的,而是由C方法调用的。如下所示,点击按钮,屏幕弹出对话框:点击对话框中的ok按钮,对话框就消失了。并吐司弹出一段文字“知道了”
该应用涉及到的知识有:
1.如何在C中使用android 的 log输出其实这些方法在C中已经做好了,只需要导入Android的Log类库,并在C中宏定义(也可以不用define定义别名,
但是这些方法名字太长,不好写,并且不是所有的方法都要宏定义,只需要定义自己需要用的就行了。比如我只定义LOGI)
#include <android/log.h> #define LOG_TAG "HHH" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG, __VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG, __VA_ARGS__) #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG, __VA_ARGS__)
通过
#include <android/log.h>点击进入log.h文件,可以看到具体的方法,导入完成后,一定要Android.mk文件中写入LOCAL_LDLIBS += -llog,这样写表示在编译的时候加载Log类库
2 .如何在C中调用Java中的方法
与Java的反射机制十分相似
1) 获取类的字节码文件
(*env)->FindClass(…)
2) 获取方法名(即方法的id)
(*env)->GetMethodID(…);
3) 调用方法
(*env)->CallVoidMethod(…)
(*env)->CallByteMethod(…)
(*env)->CallCharMethod(…)
等等。需要根据返回值调用不同的方法
注意:
1.无论是log输入日志,还是C调用了Java方法,应为这都要把字符串传递个Java去处理,所以不要有中文,否则程序崩溃。在Android JNI 调用C语言这篇文章中有解决办法。文章链接在下面步骤中有。
步骤:
1.创建Android项目
准备工作。先Add Native Support,将类库名命名为Hello,然后该C文件后缀和Android.mk文件(详情参考这篇文章Android JNI 调用C语言)。C文件内容暂时不需要些。
2.布局文件
编写activity_main.xml文件:
<LinearLayout 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" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="hhh.exercise.ujni_e.MainActivity" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="click1" android:text="C调用Java方法" /> </LinearLayout>
布局文件就一个按钮
3.Activity
编写MianActivity.java文件:
import android.app.Activity; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.DialogInterface; import android.os.Bundle; import android.view.View; import android.widget.Toast; public class MainActivity extends Activity { static{ System.loadLibrary("Hello"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void click1(View v) { helloC(); } public native void helloC(); // 该方法让C语言调用,然后在界面上显示一个对话框 public void show(String message) { Builder builder = new Builder(this); builder.setTitle("C调用Java中的方法"); builder.setMessage(message); // 设置取消按钮 builder.setNegativeButton("ok", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this, "知道了", 1).show(); } }); AlertDialog dialog = builder.create(); dialog.show(); } }
从代码中可以看出click1方法并没有调用show方法,也就是说,如果点击按钮后显示了对话框,说明是本地方法helloC调用的show方法。
4.C文件
#include <jni.h> #include <android/log.h> // 宏定义类似java 层的定义,不同级别的Log LOGI, LOGD, LOGW, LOGE, LOGF。 对就Java中的 Log.i log.d #define LOG_TAG "HHH" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG, __VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG, __VA_ARGS__) #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG, __VA_ARGS__) JNIEXPORT void JNICALL Java_hhh_exercise_ujni_1e_MainActivity_helloC (JNIEnv * env, jobject obj){ LOGD("Hello Java"); LOGI("hello C "); //使用反射技术,获取Java中的方法 // jclass (*FindClass)(JNIEnv*, const char*); //第二个参数:Java类的类名,要包含前面的包名 jclass clazz=(*env)->FindClass(env,"hhh/exercise/ujni_e/MainActivity"); LOGI("获得字节码文件: "); //拿到方法的ID //jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); //第三个参数:传入需要反射的方法名 //第四个参数:方法的签名 jmethodID methodID=(*env)->GetMethodID(env,clazz,"show","(Ljava/lang/String;)V"); //调用方法 //void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); //后面的三个点表示参数,可以输入任意多个。但是要注意,一定要输入Java类型的参数.不要输入中文,会乱码到导致错误(如果需要输入中文,就要进行转码) (*env)->CallVoidMethod(env,obj,methodID,(*env)->NewStringUTF(env,"what fuck")); }
可以看到,C中调用了Java中自定义的show方法,实际上就是用了反射技术。还有调用了系统已经做好的Log。
5.Android.mk
因为在C中调用了Java的Log,需要在Android.mk文件中配置:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_LDLIBS += -llog LOCAL_MODULE := Hello LOCAL_SRC_FILES := Hello.c include $(BUILD_SHARED_LIBRARY)
即在文件中添加一句LOCAL_LDLIBS += -llog
即可。
整个demo完成
相关文章推荐
- Android-本地方法与Java相互调用-自定义ProgressBar(锅炉压力监测例子)/NDK-JNI开发实例(七)
- Android jni 使用C语言调用java中的log方法
- 【我的Android进阶之旅】Android调用JNI出错 java.lang.UnsatisfiedLinkError: No implementation found for的解决方法
- Android JNI中C调用Java方法
- 【学习Android NDK开发】Java通过JNI调用native方法
- Android-java调用本地方法返回字符串显示在界面上/NDK-JNI开发实例(二)
- 模仿android_debug_JNITest实现apk 调用framework java JNI中方法
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- Android-本地方法C调用Java中的方法/NDK-JNI开发实例(六)
- Android JNI 通过C/C++调用JAVA方法
- android之JNI参数传递 (Java方法调用)
- Android JNI开发之c语言调用java方法
- JNI学习笔记:(1)开篇(2)本地代码访问Java代码 (3)本地方法取得Java属性/调用java方法 (4)本地代码创建Java对象(包括javaString) (5) 本地方法处理java数组
- 02_JNI中Java代码调用C代码,Android中使用log库打印日志,javah命令的使用,Android.mk文件的编写,交叉编译
- 对话框子视图Android自定义Dialog二次调用报错解决方法:The specified child already has a parent. You must call removeView()-java教程
- Android 在JNI中执行Java方法--C/C++调用Java
- Android JNI开发,C调用Java方法遇到的问题
- Android JNI反射调用Java构造方法、成员方法和静态方法
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- Android JNI开发(2)--native方法调用Java方法