zoukankan      html  css  js  c++  java
  • Android中关于JNI 的学习(零)简单的样例,简单地入门

    Android中JNI的作用,就是让Java可以去调用由C/C++实现的代码,为了实现这个功能。须要用到Anrdoid提供的NDK工具包,在这里不讲怎样配置了,好麻烦,配置了好久。

    本质上,Java去调用C/C++的代码事实上就是去调用C/C++提供的方法。所以,第一步,我们要创建一个类,而且定义一个Native方法。例如以下:

    JniTest类:

    public class JniTest {
    
    	public native String getTestString();
    }
    

    能够看到,在这种方法的前面,用到了nativekeyword。

    接着,我们要在命令行中编译这个java文件。得到一个class文件。例如以下:


    然后我们能够利用javah命令文件。生成一个C的头文件。事实上javah这一步没必要的,由于创建这个头文件,仅仅是为了方便我们复制这个Jni中相应的方法名称,由于这些名称实在太复杂了。 

    在这里有一点要注意,javah命令要在包的根文件夹下调用,相应的类文件,必须是完整的类名,如上图所看到的。会先回到src文件夹。再调用javah命令。

    这样我们就会在src目录下在产生一个头文件。例如以下图所看到的:


    我们能够看到其名称是com_lms_jni_JniTest.h,事实上就是包名+类名,我们能够看看里面的内容:

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_lms_jni_JniTest */
    
    #ifndef _Included_com_lms_jni_JniTest
    #define _Included_com_lms_jni_JniTest
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_lms_jni_JniTest
     * Method:    getTestString
     * Signature: ()Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_com_lms_jni_JniTest_getTestString
      (JNIEnv *, jobject);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    我们能够看到。在这里面有一个方法,名称是Java_com_lms_jni_JniTest_getTestString,够复杂吧。事实上假设我们知道这个名称规则,而且知道怎样去实现这样一个方法的话,我们是全然能够不生成这个头文件的。我们能够直接写出相应的C文件。

    接下来,在jni文件里创建一个相应的C文件。名称是值得并无所谓,但为了统一。我们就把它叫JniTest.c吧。例如以下:


    在这里,我们也把com_lms_jni_JniTest.h也放到这里了,这个事实上是没关系的,仅仅是为了内容的协调和统一而已,普通情况下,我们会把所以由C/C++实现的文件都放在项目文件夹下一个叫 jni 的文件夹以下。

    以下是在JniTest.c中实现native方法,getTestString。例如以下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <jni.h>
    
    JNIEXPORT jstring JNICALL Java_com_lms_jni_JniTest_getTestString
      (JNIEnv *e, jobject obj){
    	return (**e).NewStringUTF(e,"Hello from JniTest Function");
    }
    

    在这个c文件里,我们看到。并没有引用头文件com_lms_jni_JniTest.h,而仅仅是引用了一般的C/C++库文件,比方stido.h和stdlib.h文件等,在这里注意到一点。我们还会引用jni.h文件,jni.h文件是JNI编程中非常重要的一个头文件,关于Java中的数据类型跟jni中的数据类型的相应所有是在这个文件里定义的,兴许会来看一下这个jni.h文件。

    在上面JniTest.c文件里实现了方法之后。关于C/C++这边的实现事实上也就实现了。那么接下来就是要将这个C文件编译成so文件由Android来调用。

    为什么是so文件呢,这是由于Android本质上就是一个linux系统。所以其调用的JNI库文件,都是so形式。

    Android提供的NDK库提供了ndk-build的命令来实现这个编译过程。但在此之前,我们要先创建一个Android.mk文件。这是一个简单的小小的Make文件,其内容例如以下:

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := com_lms_jni_HwDemo
    LOCAL_SRC_FILES := 
    HwDemo.c 
    JniTest.c 
    
    include $(BUILD_SHARED_LIBRARY)

    在这里。我们会定义几个变量:

    LOCAL_PATH:其值是call my-dir,而my-dir是个宏函数,会返回Android.mk所在的路径,在这里,就是jni目录。

    include $(CLEAR_VARS),这个命令会清除掉全部LOCAL开头的变量,比方LOCAL_MODULE之类的,但有一个例外,就是其上面的LOCAL_PATH 。

    LOCAL_MODULE:要生成的so包名,也是Android中Java代码载入时的名称。

    LOCAL_SRC_FILES:要进行编译的源文件。如在这里。有HwDemo.c和JniTest.c等。

    include $(BUILD_SHARED_LIBRARY):表明生成一个动态链接库。

    定义后这样一个Android.mk文件之后,在命令行中调用ndk-build命令,例如以下:


    命令实行之后,我们能够在项目文件夹下看到libs中多了一个so库。例如以下:


    到这里,关于Jni实现的就结束了,接下来就是怎样在Android中使用这个本地方法了。

    我们创建了一个Activity,在它里面仅仅放置一个TextView控件,它的布局例如以下:

    <?

    xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/tvJni" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="test" /> </LinearLayout>


    然后在Activity中,我们要载入这个so库。例如以下:

    public class HwDemo extends Activity {
    
    	static {
    		System.loadLibrary("com_lms_jni_HwDemo");//载入so库
    	}
    	
    	public native String printHello();	
    
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);		
    		setContentView(R.layout.main);
    		TextView tv = (TextView)findViewById(R.id.tvJni);
    		JniTest jniTest = new JniTest();//调用JniTest文件的方法
    		tv.setText(jniTest.getTestString());
    	}
    
    }

    1)利用static静态代码块,载入so库文件。能够看到在这里,这个名称就是Anrdoid.mk中定义的LOCAL_MODULE值。

    2)创建JniTest对象,调用其getTestString()方法,终于显示结果例如以下:


    到这里,通过一个简单的样例,我们明确了怎样在Android中利用JNI来调用C/C++的方法了。

    最后,我们总结一下这几个步骤:

    1)创建Java类文件。并定义Native方法。如JniTest类。

    2)利用javac生成class文件,然后回到src文件夹,利用javah生成C/C++头文件,在这里要注意。javah命令要在包的根文件夹下调用,相应的类文件,必须是完整的类名。例如以下:

    在Src文件夹:javah com.lms.jni.JniTest。在上面的截图,也能够看到javac之后,是回到src文件夹,再调用javah。

    3)编写相应的C文件,如JniTest.c,在里面实现C/C++的方法,记得要放在jni目录以下。

    4)编写Android.mk文件,利用ndk-build命令生成so文件。

    5)在Android中利用static静态代码块,调用system.loadLibrary方法来载入so库文件。

    6)在Java逻辑中调用之前定义的JniTest类的方法。

    结束。

    源码下载

  • 相关阅读:
    字符串
    决策树
    结构体实验
    指针实验
    打印杨辉三角
    P176 1.2.3
    第七次作业
    第六次作业
    第五次作业
    第四次修改
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/6977999.html
Copyright © 2011-2022 走看看