Android NDK开发(二)编写计算器so文件之动态注册

一、创建空白项目

 二、创建控件(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 <jni.h>//引入头文件
//功能函数
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文件时最先调用,并注册方法到环境。

问题集锦:

一、加载so出错

1、检查c文件中 

FindClass(env,"com/example/jisuanqi/MainActivity");

路径是否正确。

2、找不到so文件

Android开发中so库文件的存放位置

在自己编译so库文件,或者引用第三方的so库文件时,库文件存放目录不正确经常会引起很多问题。这里总结一下。

so文件存放目录 或 默认生成目录:

  • jniLibs/CPU_ABI:对于Android Studio项目
  • libs/CPU_ABI:对于Eclipse项目
  • jni/CPU_ABI:在AAR文件中
  • lib/CPU_ABI:在APK文件中
  • 在app的nativeLibraryPath目录中:对于Android 版本<5.0 的设备
  • 在app的legacyNativeLibraryDir/CPU_ARCH目录中:对于Android版本>=5.0的设备

以上提到的CPU_ABI的可能取值如下,它的值取决于你编译的目标平台。

  • armeabi
  • armeabi-v7a
  • arm64-v8a
  • x86
  • x86_64
  • mips
  • mips64

引用so文件时,如果so文件被放在默认目录下:

  • 在Android Studio中,so文件在jniLibs/CPU_ABI下
  • 在Eclips中,so文件在jni/CPU_ABI下
    那么你不用做额外的设置。

如果so文件没有被放在默认目录下

比如在Android Studio中,so文件放在了libs目录下。则需要在build.gradle中添加设置,来指定实际存放目录。

android {
    ...
    sourceSets {
        ...
        main.jni.srcDirs = []
        main.jniLibs.srcDirs = ['libs']
    }
....

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人工智能-肥鹅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值