王学岗NDK系列(一):android高级开发之JNI编程

NDK相关的博客
1,什么是JNI
java native interface(java本地/原生接口)
JNI是一种标准,c/c++和java相互调用的标准
NDK就是基于这个 标准开发的
优点:可以利用大部分c/c++的语言库库,可以跨平台去移植代码,提升运算效率;
缺点:限制了部分java跨平台的能力,java跨平台的能力是jvm(java虚拟机),因为jni是脱离了jvm运行
2,JNI c/c++动态库
windows:.dll
Linux :.so(注:android的内核就是Linux)
Mac OSx:.jnilib
3,新建一个包含ndk的项目,我们发现它比普通项目增加了两个文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XIWQyfrw-1658988783800)(https://img-blog.csdn.net/20180207145051551?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWN6Z193eGc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)]
看下相关的类

package com.example.acer.test_02_06;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");//
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);



        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

JNIEnv类型实际上代表了Java环境,通过这个JNIEnv* 指针,就可以对Java端的代码进行操作。例如,创建Java类中的对象,调用Java对象的方法,获取Java对象中的属性等等。JNIEnv的指针会被JNI传入到本地方法的实现函数中来对Java端的代码进行操作。

JNIEnv类中有很多函数可以用:

NewObject:创建Java类中的对象

NewString:创建Java类中的String对象

NewArray:创建类型为Type的数组对象

GetField:获取类型为Type的字段

SetField:设置类型为Type的字段的值

GetStaticField:获取类型为Type的static的字段

SetStaticField:设置类型为Type的static的字段的值

CallMethod:调用返回类型为Type的方法

CallStaticMethod:调用返回值类型为Type的static方法

等许多的函数,具体的可以查看jni.h文件中的函数名称。

#include <jni.h>//引入jni的头文件
#include <string>
//允许以后的函数被编译为c的模式
 extern "C"
/**
 *  1,JNIEXPORT:允许该函数被java调用,这里是固定写法
 *  2,jstring:返回值类型
 *  3,JNICALL:jni约束函数入栈顺序和堆栈内存清理的规则
 *  4,Java_com_example_acer_test_102_106_MainActivity_stringFromJNI:
               方法名,java+项目具体的包名+类名+native方法名
 *  5,JNIEnv:java native interface environment Jave本地接口环境
           在C中:JNIEnv 指针类型
           JNIEnv* env	(*env)->方法名(env,参数列表)
           javaVM* vm	(*vm)->方法名(vm,参数列表)
           在C++中:JNIEnv 结构体类型
           JNIEnv* env	env->方法名(参数列表)
           javaVM* vm	vm->方法名(参数列表)
 */
JNIEXPORT jstring JNICALL
Java_com_example_acer_test_102_106_MainActivity_stringFromJNI(
        JNIEnv *env,
 //1-native方法不是静态的时候,jobject对应的是java中对应的对象(调用此
 //方法的对象)
 //2-native方法是静态方法,jobject对应的是调用此方法的class对象(当前类的类对象)
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

4,JNI基本数据类型和引用类型
在 JNI 开发中,我们知道,Java 的数据类型并不是直接在 JNI 里使用的,例如 int 就是使用 jint 来表示。那么,就如我们来认识一下这些数据类型吧。
Java数据类型通过JNI数据类型调用C/C++数据类型

基本数据类型
在这里插入图片描述
引用数据类型
在这里插入图片描述

c/c++类型		JNI类型		解释
uint8_t  		jboolean;		/* unsigned 8 bits */
int8_t   		jbyte;   		/* signed 8 bits */
uint16_t 		jchar;  		/* unsigned 16 bits *
int16_t  		jshort;		/* signed 16 bits */
int32_t  		jint;     	/* signed 32 bits */
int64_t  		jlong;    	/* signed 64 bits */
float    		jfloat;   		/* 32-bit IEEE 754 */
double   	    jdouble;  	/* 64-bit IEEE 754 */	
      	        jobject;	任何java对象,包括没有对应的java类的对象
      	        jclass;		Class 对象
       	        jstring;		字符串类对象
        	    jarray;		对应任何数组
        	    

5,在JVM虚拟机中,存储数据类型的名称时,是使用指定的描述符来存储,而不是我们习惯的 int,float 等。
c/c++代码调用Java类 对象的属性(类对象的成员)
在这里插入图片描述

java类型 	属性类型符号(成员类型符号)
boolean		Z
byte 		B
char		C
short		S
int			I
long		J
float		F
double		D
void		V
object		L完整类名(如String就应写为:Ljava/lang/String;);
array		[arry-type 	[数组类型
method		(参数类型)返回类型	

在MainActivity类中声明int a 成员变量,在c++中为其赋值,我们看下代码中怎么实现
(补充: jstring NewStringUTF(const char* bytes),以 UTF-8 的编码方式创建一个 Java 的字符串。bytes:指向字符数组的指针)

JNIEXPORT jstring JNICALL
Java_com_example_acer_test_102_106_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobject1/* this */) {
    jclass jcl=env->GetObjectClass(jobject1);
    jfieldID jid=env->GetFieldID(jcl,"a","I");
    jint a=45;
    env->SetIntField(jobject1,jid,45);
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

如果把MainActivity中的a改为String类型,我们看下如何修改值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JHyXIuyz-1658988783803)(https://img-blog.csdn.net/20180207180357283?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWN6Z193eGc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)]

jni方法大全

补充:
c/c++可以直接调硬件,Java需要调用c/c++;
java和c/c++在同一个进程。两个语音不同,Java调用c/c++,需要传参,比如JavaString对象,这时候需要将Java的内存对象转换为C/C++内存对象,这就是jni。NDK是工具集,

#include <jni.h>
#include <string>

extern "C"//表示兼容C,会把代码放到C中,使用gcc进行编译。不加这个代码就是c++代码,会交给g++编译
//c不支持重载,c++支持。c++编译后函数会增加参数名字,这个时候Java会找不到编译后的函数,会报错。

JNIEXPORT //宏(__attribute__ ((visibility ("default")))),代表访问权限.有两个取值,default与hidden
jstring //返回值
JNICALL //提醒你这是个jni函数,可以去掉
Java_com_example_ctest0728_MainActivity_stringFromJNI//静态注入,函数名,根据生命的Java native方法生成的,Java+包名+类名+方法名
(
        JNIEnv* env,//工具类,提供了很多转换方法
        jobject /* this */,
        jstring data
        ) {
    const char* dataC =env->GetStringUTFChars(data,0);//0表示不需要复制
    env->ReleaseStringChars(data, reinterpret_cast<const jchar *>(dataC));//释放
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());//hello.c_str()转化为指针数组,C++字符串是对象但C没有对象,c里面的字符串就是指针数组
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值