一、创建空白项目
二、创建控件(2个输入框、4个按钮分别id为:add,sub,mul,div)
三、为控件添加事件:
package com.example.ndk_dongtaizhuce;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
//声明变量
private EditText first;
private EditText second;
private Button add;
private Button sub;
private Button mul;
private Button div;
private float one;
private float two;
//加载JNI文件
static {
System.loadLibrary("jisuanqi");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化控件
init();
//开始运算
yunsuan();
}
private void yunsuan(){
//为按钮添加事件
View.onClickListener cl = new View.onClickListener() {
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.add:
//获取两个编辑框的值
one = Float.parseFloat(first.getText().toString());
two = Float.parseFloat(second.getText().toString());
//显示
Toast.makeText(MainActivity.this,add(one,two)+"",Toast.LENGTH_LONG).show();
break;
case R.id.sub:
//获取两个编辑框的值
one = Float.parseFloat(first.getText().toString());
two = Float.parseFloat(second.getText().toString());
Toast.makeText(MainActivity.this,sub(one,two)+"",Toast.LENGTH_LONG).show();
break;
case R.id.mul:
//获取两个编辑框的值
one = Float.parseFloat(first.getText().toString());
two = Float.parseFloat(second.getText().toString());
Toast.makeText(MainActivity.this,mul(one,two)+"",Toast.LENGTH_LONG).show();
break;
case R.id.div:
//获取两个编辑框的值
one = Float.parseFloat(first.getText().toString());
two = Float.parseFloat(second.getText().toString());
Toast.makeText(MainActivity.this,div(one,two)+"",Toast.LENGTH_LONG).show();
break;
default:
break;
}
}
};
add.setonClickListener(cl);
sub.setonClickListener(cl);
mul.setonClickListener(cl);
div.setonClickListener(cl);
}
//初始化控件
private void init(){
//绑定两个编辑框
first = (EditText) findViewById(R.id.editText);
second = (EditText) findViewById(R.id.editText2);
//绑定四个按钮
add = (Button) findViewById(R.id.add);
sub = (Button) findViewById(R.id.sub);
mul = (Button) findViewById(R.id.mul);
div = (Button) findViewById(R.id.div);
}
//定义native方法,实现在so层
public native float add(float one,float two);
public native float sub(float one,float two);
public native float mul(float one,float two);
public native float div(float one,float two);
}
在app目录下创建新目录命名为JNI,创建jisuanqi.c文件
编写以下代码:
#include//引入头文件 //功能函数 jfloat addc(JNIEnv* env,jobject obj,jfloat a,jfloat b){ return a + b; } jfloat subc(JNIEnv* env,jobject obj,jfloat a,jfloat b){ return a - b; } jfloat mulc(JNIEnv* env,jobject obj,jfloat a,jfloat b){ return a * b; } jfloat divc(JNIEnv* env,jobject obj,jfloat a,jfloat b){ return a / b; } //绑定C层和java层 JNINativeMethod nativeMethod[]={ {"add","(FF)F",(void*)addc}, {"sub","(FF)F",(void*)subc}, {"mul","(FF)F",(void*)mulc}, {"div","(FF)F",(void*)divc}, }; //注册函数 jint registerNative(JNIEnv* env){ //获取类 jclass clazz = (*env)->FindClass(env,"com/example/ndk_dongtaizhuce/MainActivity"); //注册方法 env:this、clazz:类、nativeMethod:注册方法、注册函数个数 if((*env)->RegisterNatives(env,clazz,nativeMethod,sizeof(nativeMethod)/sizeof(nativeMethod[0]))!=JNI_OK){ return JNI_ERR; } return JNI_OK; } //使用JNI_OnLoad进行动态注册 JNIEXPORT jint JNICALL JNI_onLoad(JavaVM* vm,void* reserved){ JNIEnv* env; //vm,void**:二级指针,JNI_VERSION_1_4:jni版本 if( (*vm)->GetEnv(vm,(void**)&env,JNI_VERSION_1_4)!=JNI_OK){ return JNI_ERR; } if(registerNative(env)!=JNI_OK){ return JNI_ERR; } return JNI_VERSION_1_4; }
新建Android.mk和Application.mk
#Android.mk文件 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := jisuanqi #模块名称 LOCAL_SRC_FILES := jisuanqi.c #源文件 .c或者.cpp LOCAL_ARM_MODE := arm #编译后的指令集 ARM指令 LOCAL_LDLIBS += -llog #依赖库 include $(BUILD_SHARED_LIBRARY) #指定编译文件的类型 #Application.mk文件 APP_ABI := all
cmd来到当前文件夹下:ndk-build
表示成功。
一、静态注册和动态注册的区别:
静态方法文件名过长:Java+包名+类名+方法名(native方法)
例:Java_com_example_demo_1jni_MainActivity_getstring
调用native方法时速度慢。
动态方法:有JNINativeMethod函数映射表,调用时查找速度快,方法名可以自定义。
JNI_OnLoad方法在启动so文件时最先调用,并注册方法到环境。



