JNI(Java Native Interface,Java本地接口)定义&作用: 用于打通Java层与Native(C/C++)层。
JNI注册的两种时机:
1)Android系统启动过程中Zygote注册,可通过查询AndroidRuntime.cpp中的gRegJNI,看看是否存在对应的register方法;
2)调用System.loadLibrary()方式注册。
JNI接口的组织类似于C++虚拟函数表,指向不同的接口函数
首先明白native方法名和文件名的命名规律,其次要懂得该如何去搜索代码。
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
JNI开发流程
从java层到c+层
参考:JNI动态注册 https://blog.csdn.net/hjf161105/article/details/79543808
编写java类,声明了native方法
编写native代码(c语言)
将native代码编译成so文件
在java类中引入so库,调用native方法
,
实例分析:引用自:https://www.cnblogs.com/anni-qianqian/p/5574039.html
使用C语言实现本地方法
- 在项目根目录下创建jni文件夹
- 在jni文件中创建一个c文件
- 在java代码中,创建一个本地方法helloFromC
//native关键字
public native String helloFromC();
4. 在jni中定义函数实现这个方法,函数名必须为
//返回值 报名_类名_方法名(参数参照例子)
jstring Java_com_itheima_helloworld1_MainActivity_helloFromC(JNIEnv* env, jobject obj)
5. 返回一个字符串,用c定义一个字符串
char* cstr = “hello from c”;
6. 把c的字符串转换成java的字符串
jstring jstr = (*env)->NewStringUTF(env, cstr);
return jstr;
7. 在jni中创建Android.mk文件
8. 在c文件中添加<jni.h>头文件
9. 在jni文件夹下执行ndk-build.cmd指令
10. java代码中加载so类库,调用本地方法(so是C语言的类库)
static{
//加载打包完毕的so类库
System.loadLibrary(“hello”);
}
代码
MainActivity
public class MainActivity extends Activity {
static{
//加载打包完毕的so类库
System.loadLibrary("hello");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void click(View v){
Toast.makeText(this, helloFromC(), 0).show();
}
//定义一个本地方法,方法体由c语言实现
public native String helloFromC();
}
Hello.c
#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
jstring Java_com_itheima_helloworld1_MainActivity_helloFromC(JNIEnv* env, jobject obj){
//c语言的字符串
char* cstr = “hello from c”;
//把C语言的字符串转换成java的字符串
// jstring (NewStringUTF)(JNIEnv, const char*);
// jstring jstr = (*(*env)).NewStringUTF(env, cstr);
jstring jstr = (*env)->NewStringUTF(env, cstr);
return jstr;
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#编译生成的文件的类库叫什么名字
LOCAL_MODULE := hello
#要编译的c文件
LOCAL_SRC_FILES := Hello.c
include $(BUILD_SHARED_LIBRARY)
- 实现两个数相加
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 click(View v){
Toast.makeText(this, "3+5的和为" + add(3, 5), 0).show();
}
public native int add(int i, int j);
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello
LOCAL_SRC_FILES := Hello.c
include $(BUILD_SHARED_LIBRARY)
Hello.c
#include <jni.h>
jint Java_com_itheima_helloworld2_MainActivity_add(JNIEnv* env, jobject obj, jint i, jint j){
return i + j;
}
Application.mk
APP_ABI := all //支持arm、mips、x86等所有架构
- javah
1.7:在src目录下执行javah 包名.类名
1.6:在bin/classes目录下执行
然后工程刷新,复制里面已经自动生成的方法名,就可以粘贴到c文件中使用
,
https://blog.csdn.net/c10WTiybQ1Ye3/article/details/107010668
jni实例分析:https://www.jianshu.com/p/0f34c097028a
用了jni,在c文件中有了jint,jclass,jlong等是入参。是jini的int,long等类型。理解为jint=int
为java传入的参数。
- static register native function
- dynamic register native function
i) coding java native function
ii) product .h headfile
iii) RegisterNatives:put c/c++ function map to java function
JNI_OnLoad 即jni 的main
程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,
通过Java的类加载机制(ClassLoader)来动态加载某个class文件到内存当中的,
从而只有class文件被载入到了内存之后,才能被其它class所引用
,
反射:
运行状态获取class的对象,构造函数,方法等.
学习反射之前,需要先学习类的加载过程:Java虚拟机基础——3类加载机制:https://www.jianshu.com/p/443ca5b1e8b2
使用实例:
Class actionClass=Class.forName(“MyClass”);
Object action=actionClass.newInstance();
Method method = actionClass.getMethod(“myMethod”,null);
method.invoke(action,null);
反射:https://zhuanlan.zhihu.com/p/270939753
实例:https://lixuekai.blog.csdn.net/article/details/52255363
https://lixuekai.blog.csdn.net/article/details/52254924