androidjni(Androidjni编程)

本篇文章给大家谈谈androidjni,以及Androidjni编程对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

如何在android源码中添加自己的jni方法

1,、 项目实现了一个简单的四则运算,项目的目录层次如下:

AndroidManifest.xml Android.mk jni res src

资源文件简简单单,一个布局文件,稍后会有demo的下载地址

主要记录备忘的内容如下:

MainActivity.Java

[html] view plain copypublic native int add(int x, int y);

public native int substraction(int x, int y);

public native float multiplication(int x, int y);

public native float division(int x, int y);

static{

System.loadLibrary("arithmetic");

}

2、生成lib的名称为libarithmetic.so.注意load的时候写"arithmetic"

jni 目录下有两个文件,一个是Android.mk,一个是c++源文件long.cpp

jni/Android.mk如下:

[html] view plain copyLOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_MODULE:= libarithmetic

LOCAL_SRC_FILES:= \

long.cpp

LOCAL_SHARED_LIBRARIES := \

libutils

LOCAL_STATIC_LIBRARIES :=

LOCAL_C_INCLUDES += \

$(JNI_H_INCLUDE)

LOCAL_CFLAGS +=

LOCAL_PRELINK_MODULE := false

include $(BUILD_SHARED_LIBRARY)

3、 注释:

LOCAL_PATH(必须定义,而且要第一个定义),宏函数‘my-dir’, 由编译系统提供,用于返罩游回当前路径(即包含Android.mk

file文件的目录);

include $( CLEAR_VARS),

CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE,

LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH

。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的;

LOCAL_MODULE_TAGS :=user eng tests optional

user: 指该模块只在user版本下才编译

eng: 指该模块只在eng版本下才编译

tests: 指该模块只在tests版本下才编译

optional:指该模块在所有版本下都编译

LOCAL_MODULE(必须定义),标识模闷信你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。Note:编译系统会自动产生合适的前缀和后缀,例如:arithmetic编译成功后将生成libarithmetic.so库文件

LOCAL_SRC_FILES 变量必须包含将要编译打包进模块中源代码文件。不旦轮用在这里列出头文件和包含文件。

LOCAL_SHARED_LIBRARIES中加入所需要链接的动态库(*.so)的名称

LOCAL_STATIC_LIBRARIES加入所需要链接的静态库(*.a)的名称

LOCAL_CFLAG可选的编译器选项,用法之一是定义宏,例如LOCAL_CFLAGS := -Werror作用是编译警告也作为错误信息

LOCAL_PRELINK_MODULE:=false,不作prelink处理,默认是要prelink操作的,有可能造成地址空间冲突(这地方目前还不明白)

long.cpp源代码如下:

[html] view plain copy#define LOG_TAG "LongTest2 long.cpp"

#include

#include

#include "jni.h"

jint add(JNIEnv *env, jobject thiz, jint x, jint y){

return x + y;

}

jint substraction(JNIEnv *env, jobject thiz, jint x, jint y){

return x - y;

}

jfloat multiplication(JNIEnv *env, jobject thiz, jint x, jint y){

return (float)x * (float)y;

}

jfloat division(JNIEnv *env, jobject thiz, jint x, jint y){

return (float)x/(float)y;

}

static const char *classPathName = "com/inspur/test2/MainActivity";

static JNINativeMethod methods[]= {

{"add", "(II)I", (void*)add},

{"substraction", "(II)I", (void*)substraction},

{"multiplication", "(II)F", (void*)multiplication},

{"division", "(II)F", (void*)division},

};

typedef union{

JNIEnv* env;

void* venv;

}UnionJNIEnvToVoid;

static int registerNativeMethods(JNIEnv* env, const char* className,

JNINativeMethod* gMethods, int numMethods){

jclass clazz;

clazz = env-FindClass(className);

if (clazz == NULL)

return JNI_FALSE;

if (env-RegisterNatives(clazz, gMethods, numMethods)0)

return JNI_FALSE;

return JNI_TRUE;

}

static int registerNatives(JNIEnv *env){

if (!registerNativeMethods(env, classPathName,

methods, sizeof(methods)/sizeof(methods[0])))

{

return JNI_FALSE;

}

return JNI_TRUE;

}

jint JNI_OnLoad(JavaVM* vm, void* reserved){

UnionJNIEnvToVoid uenv;

uenv.venv = NULL;

jint result = -1;

JNIEnv *env = NULL;

if (vm-GetEnv(uenv.venv, JNI_VERSION_1_4) != JNI_OK){

goto bail;

}

env = uenv.env;

env = uenv.env;

if (registerNatives(env) != JNI_TRUE){

goto bail;

}

result = JNI_VERSION_1_4;

bail:

return result;

}

除了利用 编写native JAVA类,通过javah生成.h文件,根据.h文件编写.c/cpp文件

方法外(名字像老太太的裹脚步,又臭又长,而且不灵活),Android还可以通过引用JNI_Onload方式实现。jint JNI_onLoad(JavaVM*

vm, void* reverced),改方法在so文件被加载时调用。

JNI_OnLoad()有两个重要的作用:

指定JNI版本:告诉VM该组件使用那一个JNI版本(若未提供JNI_OnLoad()函数,VM会默认该使用最老的JNI

1.1版),如果要使用新版本的JNI,例如JNI

1.4版,则必须由JNI_OnLoad()函数返回常量JNI_VERSION_1_4(该常量定义在jni.h中) 来告知VM。

初始化设定,当VM执行到System.loadLibrary()函数时,会立即先呼叫JNI_OnLoad()方法,因此在该方法中进行各种资源的初始化操作最为恰当。

JNI_OnUnload()的作用与JNI_OnLoad()对应,当VM释放JNI组件时会呼叫它,因此在该方法中进行善后清理,资源释放的动作最为合适。

4、 项目根目录下Android.mk文件:

[html] view plain copyLOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_JNI_SHARED_LIBRARIES := libarithmetic

LOCAL_PACKAGE_NAME := LongTest

LOCAL_SHARED_LIBRARIES := \

libutils\

liblog

include $(BUILD_PACKAGE)

include $(LOCAL_PATH)/jni/Android.mk

# Also build all of the sub-targets under this one: the shared library.

include $(call all-makefiles-under,$(LOCAL_PATH))

LOCAL_PACKAGE_NAME:项目名称,即最终生成apk的名字

LOCAL_JNI_SHARED_LIBRARIES := libxxx就是把so文件放到apk文件里的libs/armeabi里

执行BUILD_PACKAGE。它的定义也是在config.mk中定义如下:BUILD_PACKAGE:=

$(BUILD_SYSTEM)/package.mk

$(call all-java-files-under, src)编译的源代码文件列表添加src目录下所有的java 源文件

$(call all-makefiles-under, $(LOCAL_PATH))编译器会在编译完当前目录下的文件后再深入子目录编译

如果make过android源码,可以在项目根目录下执行mm命令进行编译。前提是执行过source

androidSRC/build/envsetup.sh

或者直接把source androidSRC/build/envsetup.sh添加到~/.bashrc中,会更加方便

android中如何将JNI整合到系统中

1、首先 要编写相应的mk文件,是系统编译时能将jni编译进系统

(1) apk对应的mk文件:

LOCAL_PATH:= $(call my-dir)

# the library

# ============================================================

include $(CLEAR_VARS)

LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_MODULE_TAGS := optional

LOCAL_PACKAGE_NAME := e

LOCAL_CERTIFICATE := platform

include $(BUILD_PACKAGE)

# additionally, build unit tests in a separate .apk

include $(call all-makefiles-under,$(LOCAL_PATH))

(瞎高2)jni对应的mk文件:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := libhello-jni

LOCAL_SRC_FILES := hello-jni.c

include $(BUILD_SHARED_LIBRARY)

2、在系统中声明:路径build/core/user_tags.mk

本例子磨尺尺中在上述文件最后添加 libhello-jni \

3、全编系统代码,则可以正常生成jni对困搏应的so文件了

如何在Android下使用JNI

1.引言

我们知道,Android系统的底层库由c/c++编写,上层Android应用程序通过Java虚拟机调用底层接口,衔接底层c/c++库与Java应用程序间的接口正是JNI(JavaNative Interface)。本文描述了如何在ubuntu下配置AndroidJNI的开发环境,以及如何编写一个简单的c函数库和JNI接口,并通过编写Java程序调用这些接口,最终运行在模拟器上的过程。

2.环境配置

2.1.安装jdk1.6

(1)从jdk官方网站下载jdk-6u29-linux-i586.bin文件。

(2)执行jdk安装文件

[html] view plaincopyprint?

01.$chmod a+x jdk-6u29-linux-i586.bin

02.$jdk-6u29-linux-i586.bin

$chmod a+x jdk-6u29-linux-i586.bin

$jdk-6u29-linux-i586.bin

(3)配置jdk环境变量

[html] view plaincopyprint?

01.$sudo vim /etc/profile

02.#JAVAEVIRENMENT

仿启03.exportJAVA_HOME=/usr/lib/java/jdk1.6.0_29

04.exportJRE_HOME=$JAVA_HOME/jre

05.念大虚exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH

06.exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH

$sudo vim /etc/profile

#JAVAEVIRENMENT

exportJAVA_HOME=/usr/lib/java/jdk1.6.0_29

exportJRE_HOME=$JAVA_HOME/jre

exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH

exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH

保存后退出编辑,并重启系统。

(4)验证安装

[html] view plaincopyprint?

01.$java -version

02.javaversion "1.6.0_29"

03.Java(TM)SE Runtime Environment (build 1.6.0_29-b11)

04.JavaHotSpot(TM) Server VM (build 20.4-b02, mixed mode)

05.$javah

06.用法:javah[选项]类

07.其中[选项]包括:

08.-help输出此帮助消息并退出

09.-classpath路径用于装入类的路径

10.-bootclasspath路径用于装入引导类的路径

11.-d目录输出目录

12.-o文件输出文件(只能使用-d或-o中的一个)

13.-jni生成JNI样式的头文件(默认)

14.-version输出版本信息

15.-verbose启用详细输出

16.-force始终写入输出文件

17.使用全限定名称指定类(例

18.如,java.lang.Object)。

$java -version

javaversion "1.6.0_29"

Java(TM)SE Runtime Environment (build 1.6.0_29-b11)

JavaHotSpot(TM) Server VM (build 20.4-b02, mixed mode)

$javah

用法:javah[选项]类

其中[选项]包括:

-help输出此帮助消息并退出

-classpath路径用于装入类仔燃的路径

-bootclasspath路径用于装入引导类的路径

-d目录输出目录

-o文件输出文件(只能使用-d或-o中的一个)

-jni生成JNI样式的头文件(默认)

-version输出版本信息

-verbose启用详细输出

-force始终写入输出文件

使用全限定名称指定类(例

如,java.lang.Object)。2.2.安装android应用程序开发环境

ubuntu下安装android应用程序开发环境与windows类似,依次安装好以下软件即可:

(1)Eclipse

(2)ADT

(3)AndroidSDK

与windows下安装唯一不同的一点是,下载这些软件的时候要下载Linux版本的安装包。

安装好以上android应用程序的开发环境后,还可以选择是否需要配置emulator和adb工具的环境变量,以方便在进行JNI开发的时候使用。配置步骤如下:

把emulator所在目录android-sdk-linux/tools以及adb所在目录android-sdk-linux/platform-tools添加到环境变量中,android-sdk-linux指androidsdk安装包android-sdk_rxx-linux的解压目录。

[plain] view plaincopyprint?

01.$sudo vim /etc/profile

02.exportPATH=~/software/android/android-sdk-linux/tools:$PATH

03. exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH

$sudo vim /etc/profile

exportPATH=~/software/android/android-sdk-linux/tools:$PATH

exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH

编辑完毕后退出,并重启生效。

2.3.安装NDK

NDK是由android提供的编译android本地代码的一个工具。

(1)从androidndk官网下载ndk,目前最新版本为android-ndk-r6b-linux-x86.tar.bz2.

(2)解压ndk到工作目录:

[plain] view plaincopyprint?

01.$tar -xvf android-ndk-r6b-linux-x86.tar.bz2

02.$sudo mv android-ndk-r6b /usr/local/ndk

$tar -xvf android-ndk-r6b-linux-x86.tar.bz2

$sudo mv android-ndk-r6b /usr/local/ndk

(3)设置ndk环境变量

[plain] view plaincopyprint?

01.$sudo vim /etc/profile

02.exportPATH=/usr/local/ndk:$PATH

$sudo vim /etc/profile

exportPATH=/usr/local/ndk:$PATH

编辑完毕后保存退出,并重启生效

(4)验证安装

[plain] view plaincopyprint?

01.$ cd/usr/local/ndk/samples/hello-jni/

02.$ ndk-build

03.Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver

04.Gdbsetup : libs/armeabi/gdb.setup

05.Install : libhello-jni.so = libs/armeabi/libhello-jni.so

$ cd/usr/local/ndk/samples/hello-jni/

$ ndk-build

Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver

Gdbsetup : libs/armeabi/gdb.setup

Install : libhello-jni.so = libs/armeabi/libhello-jni.so

3.JNI实现

我们需要定义一个符合JNI接口规范的c/c++接口,这个接口不用太复杂,例如输出一个字符串。接下来,则需要把c/c++接口的代码文件编译成共享库(动态库).so文件,并放到模拟器的相关目录下。最后,启动Java应用程序,就可以看到最终效果了。

3.1.编写Java应用程序代码

(1)启动Eclipse,新建android工程

Project:JNITest

Package:org.tonny.jni

Activity:JNITest

(2)编辑资源文件

编辑res/values/strings.xml文件如下:

编辑res/layout/main.xml文件

我们在主界面上添加了一个EditText控件和一个Button控件。

(3)编辑JNITest.java文件

 

static表示在系统第一次加载类的时候,先执行这一段代码,在这里表示加载动态库libJNITest.so文件。

再看这一段:

[java] view plaincopyprint?

01.privatenativeString GetReply();

privatenativeString GetReply();

native表示这个方法由本地代码定义,需要通过jni接口调用本地c/c++代码。

[java] view plaincopyprint?

01.publicvoidonClick(View arg0) {

02.edtName.setText(reply);

03.}

publicvoidonClick(View arg0) {

edtName.setText(reply);

}

这段代码表示点击按钮后,把native方法的返回的字符串显示到EditText控件。

(4)编译工程,生成.class文件。

3.2.用javah工具生成符合JNI规范的c语言头文件

在终端中,进入android工程所在的bin目录

[plain] view plaincopyprint?

01.$cd ~/project/Android/JNITest/bin

$cd ~/project/Android/JNITest/bin

我们用ls命令查看,可以看到bin目录下有个classes目录,其目录结构为classes/org/tonny/jni,即classes的子目录结构是android工程的包名org.tonny.jni。请注意,下面我们准备执行javah命令的时候,必须进入到org/tonny/jni的上级目录,即classes目录,否则javah会提示找不到相关的java类。

下面继续:

[plain] view plaincopyprint?

01.$cd classes

02.$javah org.tonny.jni.JNITest

03.$ls

04.org org_tonny_jni_JNITest.h

$cd classes

$javah org.tonny.jni.JNITest

$ls

org org_tonny_jni_JNITest.h

执行javahorg.tonny.jni.JNITest命令,在classes目录下会生成org_tonny_jni_JNITest.h头文件。如果不进入到classes目录下的话,也可以这样:

[plain] view plaincopyprint?

01.$javah -classpath ~/project/Android/JNITest/bin/classesorg.tonny.jni.JNITest

$javah -classpath ~/project/Android/JNITest/bin/classesorg.tonny.jni.JNITest

-classpath 参数表示装载类的目录。

3.3.编写c/c++代码

生成org_tonny_jni_JNITest.h头文件后,我们就可以编写相应的函数代码了。下面在android工程目录下新建jni目录,即~/project/Android/JNITest/jni,把org_tonny_jni_JNITest.h头文件拷贝到jni目录下,并在jni目录下新建org_tonny_jni_JNITest.c文件,编辑代码如下:

[cpp] view plaincopyprint?

01.#includejni.h

02.#includestring.h

03.#include"org_tonny_jni_JNITest.h"

04.

05.

06.JNIEXPORTjstring JNICALLJava_org_tonny_jni_JNITest_GetReply

07.(JNIEnv *env, jobject obj){

08.return(*env)-NewStringUTF(env,(char*)"Hello,JNITest");

09.}

#includejni.h

#includestring.h

#include"org_tonny_jni_JNITest.h"

JNIEXPORTjstring JNICALLJava_org_tonny_jni_JNITest_GetReply

(JNIEnv *env, jobject obj){

return(*env)-NewStringUTF(env,(char*)"Hello,JNITest");

}

我们可以看到,该函数的实现相当简单,返回一个字符串为:"Hello,JNITest"

3.4.编写Android.mk文件

在~/project/Android/JNITest/jni目录下新建Android.mk文件,android可以根据这个文件的编译参数编译模块。编辑Android.mk文件如下:

[plain] view plaincopyprint?

01.LOCAL_PATH:= $(call my-dir)

02.include$(CLEAR_VARS)

03.LOCAL_MODULE := libJNITest

04.LOCAL_SRC_FILES:= org_tonny_jni_JNITest.c

05.include$(BUILD_SHARED_LIBRARY)

LOCAL_PATH:= $(call my-dir)

include$(CLEAR_VARS)

LOCAL_MODULE := libJNITest

LOCAL_SRC_FILES:= org_tonny_jni_JNITest.c

include$(BUILD_SHARED_LIBRARY)

LOCAL_MODULE表示编译的动态库名称

LOCAL_SRC_FILES 表示源代码文件

3.5.用ndk工具编译并生成.so文件

进入到JNITest的工程目录,执行ndk-build命令即可生成libJNITest.so文件。

[plain] view plaincopyprint?

01.$cd ~/project/Android/JNITest/

02.$ndk-build

03.Invalidattribute name:

04.package

05.Install : libJNITest.so = libs/armeabi/libJNITest.so

$cd ~/project/Android/JNITest/

$ndk-build

Invalidattribute name:

package

Install : libJNITest.so = libs/armeabi/libJNITest.so

可以看到,在工程目录的libs/armeabi目录下生成了libJNITest.so文件。

3.6.在模拟器上运行

(1)首先,我们把android模拟器启动起来。进入到emulator所在目录,执行emulator命令:

[plain] view plaincopyprint?

01.$cd ~/software/android/android-sdk-linux/tools

02.$./emulator @AVD-2.3.3-V10 -partition-size 512

$cd ~/software/android/android-sdk-linux/tools

$./emulator @AVD-2.3.3-V10 -partition-size 512

AVD-2.3.3-V10表示你的模拟器名称,与在Eclipse-AVDManager下的AVDName对应,-partition-size表示模拟器的存储设备容量。

(2)接下来,我们需要把libJNITest.so文件拷贝到模拟器的/system/lib目录下,执行以下命令:

[plain] view plaincopyprint?

01.$cd ~/project/Android/JNITest/libs/armeabi/

02.$adb remount

03.$adb push libJNITest.so /system/lib

04.80 KB/s (10084 bytes in 0.121s)

$cd ~/project/Android/JNITest/libs/armeabi/

$adb remount

$adb push libJNITest.so /system/lib

80 KB/s (10084 bytes in 0.121s)

当在终端上看到有80 KB/s (10084 bytes in 0.121s)传输速度等信息的时候,说明拷贝成功。

(3)在终端上执行JNITest程序,这个我们可以在Eclipse下,右键点击JNITest工程,RunAs-Android Application,即可在模拟器上启动程序

[img]

android 为什么要使用jni

android的jni可以使用c/c++来开发,相比java而言,运行的效率提高了很多,特别是在做一些图像算法,或者游戏逻辑的时候,使用jni将大大的提高效率。比如某个游戏要采用opengl,同样加载一个由1000个多边形组成的3d模型,jni要比java运算快好几倍,顷碧厅这样就保证了游戏运行的fps不会太低。

另外一慧戚个好处就是内雀隐存管理上面,java的内存管理全部由虚拟机来管理,C++由程序员来管理,利用率上面就好多了。

等等其他优点。

既然这么多的优点,为什么一个android程序不采用纯c来开发呢?因为是android的 UI framework采用java,所以,在UI上面还是采用java来开发。

如何在android的jni线程中实现回调

JNI回调是指在c/c++代码中调用java函数,当在c/c++的线程中执行回调函数时,会信瞎闭导致回调失败。

其中一种在Android系统的解决方案是:

把c/c++中所有线程的创建,由pthread_create函数替换为由Java层的创建线程的函数AndroidRuntime::createJavaThread。

假设有c++函数:

[cpp] view plaincopy

void *thread_entry(void *args)

{

while(1)

{

printf("thread running...\n");

sleep(1);

}

}

void init()

{

pthread_t thread;

pthread_create(thread,NULL,thread_entry,(void *)NULL);

}

init()函数创建一个线程,需要在该滑裂线程中调用java类Test的回调函数Receive:

[cpp] view plaincopy

public void Receive(char buffer[],int length){

String msg = new String(buffer);

msg = "received from jni callback:" + msg;

Log.d("Test", msg);

}

首先在c++中定义回调函数指针:

[cpp] view plaincopy

//test.h

#include pthread.h

//function type for receiving data from native

typedef void (*ReceiveCallback)(unsigned char *buf, int len);

/** Callback for creating a thread that can call into the Java framework code.

* This must be used to create any threads that report events up to the framework.

*/

typedef pthread_t (* CreateThreadCallback)(const char* name, void (*start)(void *), void* arg);

typedef struct{

ReceiveCallback recv_cb;

CreateThreadCallback create_thread_cb;

}Callback;

再修改c++中的init和thread_entry函数:

[cpp] view plaincopy

//test.c

#include stdio.h

#include stdlib.h

#include pthread.h

#include sys/wait.h

#include unistd.h

#include "test.h"

void *thread_entry(void *args)

{

char *str = "i'm happy now";

Callback cb = NULL;

int len;

if(args != NULL){

cb = (Callback *)args;

}

len = strlen(str);

while(1)

{

printf("thread running...\n");

//invoke callback method to java

if(cb != NULL cb-recv_cb != NULL){

cb-recv_cb((unsigned char*)str, len);

}

sleep(1);

}

}

void init(Callback *cb)

{

pthread_t thread;

//pthread_create(thread,NULL,thread_entry,(void *)NULL);

if(cb != NULL cb-create_thread_cb != NULL)

{

cb-create_thread_cb("thread",thread_entry,(void *)cb);

}

}

然神谨后在jni中实现回调函数,以及其他实现:

[cpp] view plaincopy

//jni_test.c

#include stdlib.h

#include malloc.h

#include jni.h

#include JNIHelp.h

#include "android_runtime/AndroidRuntime.h"

#include "test.h"

#define RADIO_PROVIDER_CLASS_NAME "com/tonny/Test"

using namespace android;

static jobject mCallbacksObj = NULL;

static jmethodID method_receive;

static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {

if (env-ExceptionCheck()) {

LOGE("An exception was thrown by callback '%s'.", methodName);

LOGE_EX(env);

env-ExceptionClear();

}

}

static void receive_callback(unsigned char *buf, int len)

{

int i;

JNIEnv* env = AndroidRuntime::getJNIEnv();

jcharArray array = env-NewCharArray(len);

jchar *pArray ;

if(array == NULL){

LOGE("receive_callback: NewCharArray error.");

return;

}

pArray = (jchar*)calloc(len, sizeof(jchar));

if(pArray == NULL){

LOGE("receive_callback: calloc error.");

return;

}

//copy buffer to jchar array

for(i = 0; i len; i++)

{

*(pArray + i) = *(buf + i);

}

//copy buffer to jcharArray

env-SetCharArrayRegion(array,0,len,pArray);

//invoke java callback method

env-CallVoidMethod(mCallbacksObj, method_receive,array,len);

//release resource

env-DeleteLocalRef(array);

free(pArray);

pArray = NULL;

checkAndClearExceptionFromCallback(env, __FUNCTION__);

}

static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)

{

return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);

}

static Callback mCallbacks = {

receive_callback,

create_thread_callback

};

static void jni_class_init_native

(JNIEnv* env, jclass clazz)

{

method_receive = env-GetMethodID(clazz, "Receive", "([CI)V");

}

static int jni_init

(JNIEnv *env, jobject obj)

{

if (!mCallbacksObj)

mCallbacksObj = env-NewGlobalRef(obj);

return init(mCallbacks);

}

static const JNINativeMethod gMethods[] = {

{ "class_init_native", "()V", (void *)jni_class_init_native },

{ "native_init", "()I", (void *)jni_init },

};

static int registerMethods(JNIEnv* env) {

const char* const kClassName = RADIO_PROVIDER_CLASS_NAME;

jclass clazz;

/* look up the class */

clazz = env-FindClass(kClassName);

if (clazz == NULL) {

LOGE("Can't find class %s/n", kClassName);

return -1;

}

/* register all the methods */

if (env-RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK)

{

LOGE("Failed registering methods for %s/n", kClassName);

return -1;

}

/* fill out the rest of the ID cache */

return 0;

}

jint JNI_OnLoad(JavaVM* vm, void* reserved) {

JNIEnv* env = NULL;

jint result = -1;

LOGI("Radio JNI_OnLoad");

if (vm-GetEnv((void**) env, JNI_VERSION_1_4) != JNI_OK) {

LOGE("ERROR: GetEnv failed/n");

goto fail;

}

if(env == NULL){

goto fail;

}

if (registerMethods(env) != 0) {

LOGE("ERROR: PlatformLibrary native registration failed/n");

goto fail;

}

/* success -- return valid version number */

result = JNI_VERSION_1_4;

fail:

return result;

}

jni的Android.mk文件中共享库设置为:

[cpp] view plaincopy

LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper

最后再实现Java中的Test类:

[java] view plaincopy

//com.tonny.Test.java

public class Test {

static{

try {

System.loadLibrary("test");

class_init_native();

} catch(UnsatisfiedLinkError ule){

System.err.println("WARNING: Could not load library libtest.so!");

}

}

public int initialize() {

return native_radio_init();

}

public void Receive(char buffer[],int length){

String msg = new String(buffer);

msg = "received from jni callback" + msg;

Log.d("Test", msg);

}

protected static native void class_init_native();

protected native int native_init();

}

android 怎么封装jni

android 怎么封装jni

一、底层实现:

c档案:hardware/libhardware_legacy/power/power.c

以其中set_screen_state(int)函式为例

其Android.mk中新增:

LOCAL_MODULE:= libpower 编译成lib

LOCAL_SRC_FILES += power.c

hardware/libhardware_legacy/power/power.c

1: int

2: set_screen_state(int on)

3: {

4: QEMU_FALLBACK(set_screen_state(on));

5:

6: LOGI("*** set_screen_state %d", on);

7:

8: initialize_fds();

9:

10: LOGI("go_to_sleep eventTime=%lld now=%lld g_error=%s\n", eventTime,

11: systemTime(), strerror(g_error));

12:

13: if (g_error)

14: goto failure;

15:

16: char buf[32];

17: int len;

18: if(on)

19: len = snprintf(buf, sizeof(buf), "%s", on_state);

20: else

21: len = snprintf(buf, sizeof(buf), "%s", off_state);

22:

23: buf[sizeof(buf) - 1] = '\0';

24: len = write(g_fds[REQUEST_STATE], buf, len);

25: if(len 0) {

26: failure:

27: LOGE("Failed setting last user activity: g_error=%d\n", g_error);

28: }

29: return 0;

30: }

其标头档案power.h中:

1: #if__cplusplus

2: extern "C" { 注1

3: #endif

4: enum {

5: PARTIAL_WAKE_LOCK = 1, the cpu stays on, but the screen is off

6: FULL_WAKE_LOCK = 2 the screen is also on

7: };

8:

9: while you have a lock held, the device will stay on at least at the

10: level you request.

11: int acquire_wake_lock(int lock, const char* id);

12: int release_wake_lock(const char* id);

13:

14: true if you want the screen on, false if you want it off

15: int set_screen_state(int on);

16:

17: set how long to stay awake after the last user activity in seconds

18: int set_last_user_activity_timeout(int64_t delay);

19:

20:

21: #if __cplusplus

22: } extern "C"

23: #endif

注1:

注1:extern表示其他衫歼档的改禅类已经定义了这段程式码里面或乱的内容,这里只是做宣告。

"C”表示的一种编译和连线规约,这里为下一步c++呼叫其做准备.

比如void foo(int,int);该函式被C编译器编译后在库中的名字为_foo,

而C++编译器则会产生像_foo_int_int之类的名字用来支援函式过载和型别安全连线。

由于编译后的名字不同,C++程式不能直接呼叫C函式。

因此C++提供了一个C连线交换指定符号extern“C”来解决这个问题而不是一种语言。

C表示这段程式码可以是符合C语言的编译和连线规约的任何语言,如Fortran、assembler等。

二、cpp构成jni桥梁

一个CPP档案呼叫之,则需新增其标头档案,比如frameworks/base/core/jni/android_os_Power.cpp.

1: #include "JNIHelp.h"

2: #include "jni.h"

3: #include "android_runtime/AndroidRuntime.h"

4: #include hardware_legacy/power.h

5: namespace android{

6: ....

7:

8: 定义函式:

9: static int setScreenState(JNIEnv *env, jobject clazz, jboolean on)

10: {

11: return set_screen_state(on);以此实现cpp到c的呼叫

12: }

13:

14: static JNINativeMethod method_table[] = {此处实现java对cpp的呼叫转化 注2

15: { "acquireWakeLock", "(ILjava/lang/String;)V", (void*)acquireWakeLock },

16: { "releaseWakeLock", "(Ljava/lang/String;)V", (void*)releaseWakeLock },

17: { "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout },

18: { "setScreenState", "(Z)I", (void*)setScreenState },

19: { "shutdown", "()V", (void*)android_os_Power_shutdown },

20: { "rebootNative", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot },

21: };

22: int register_android_os_Power(JNIEnv *env) 此处注册jni

23: { 向VM(即AndroidRuntime)登记 gMethods[]表格所含的本地函式

24: return AndroidRuntime::registerNativeMethods(

25: env, "android/os/Power",

26: method_table, NELEM(method_table));

27: }

28: };

注2:

typedef struct {

const char* name; Java中函式的名字

const char* signature; 用字串是描述了函式的引数和返回值

void* fnPtr; 函式指标,指向C函式

} JNINativeMethod;

其中比较难以理解的是第二个引数,例如

"()V"

"(II)V"

"(Ljava/lang/String;Ljava/lang/String;)V"

实际上这些字元是与函式的引数型别一一对应的。

"()" 中的字元表示引数,后面的则代表返回值。例如"()V" 就表示void Func();

"(II)V" 表示 void Func(int, int);

具体的每一个字元的对应关系如下

字元 Java型别 C型别

V void void

Z jboolean boolean

I jint int

J jlong long

D jdouble double

F jfloat float

B jbyte byte

C jchar char

S jshort short

阵列则以"["开始,用两个字元表示

[I jintArray int[]

[F jfloatArray float[]

[B jbyteArray byte[]

[C jcharArray char[]

[S jshortArray short[]

[D jdoubleArray double[]

[J jlongArray long[]

[Z jbooleanArray boolean[]

上面的都是基本型别。如果Java函式的引数是class,则以"L"开头,以";"结尾中间是用"/" 隔开的包及类名。而其对应的C函式名的引数则为jobject. 一个例外是String类,其对应的类为jstring

Ljava/lang/String; String jstring

Ljava//Socket; Socket jobject

如果JAVA函式位于一个嵌入类,则用$作为类名间的分隔符。

例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"

三、java的封装实现

frameworks/base/core/java/android/os/Power.java 此处路径跟cpp中注册jni处的路径是一致的.待细研究是否有关系

1: package android.os;

2: public class Power

3: {

4: ...

5: public static native int setScreenState(boolean on); 被native修饰的表示呼叫了非java语言的本地方法

6: ...

7: }

四、java中对其呼叫

frameworks/base/services/javaandroid/server/PowerManagerService.java

import android.os.Power;

public class PowerManagerService extends IPowerManager.Stub

implements LocalPowerManager, Watchdog.Monitor {

...

int err = Power.setScreenState(on);

...

}

android size 怎么封装

[] view plain copy print?

resources

!-- Base application theme. --

style name=AppTheme parent="Theme.AppCompat.Light.NoActionBar"

!-- Customize your theme here. --

item name=colorPrimary@color/colorPrimary/item

item name=colorPrimaryDark@color/colorPrimaryDark/item

item name=colorAent@color/colorAent/item

/style

style name=text_18_ffffff

item name=android:textSize18

android怎么封装customsharelistener

以下专案所需要的jar包,图片等资源可到该网站下载SDK即可。

连结::dev.umeng./social/android/quick-integration?spm=0.0.0.0.LkoxNn

首先要引入相应的jar包,我用了友盟整合的jar包,选择相应的进行汇入。

在下载的SDK中有一个工具:umeng_integrate_tool.jar,使用它生成自己想要的jar包和资源

方法一: 百度一下“安智市场” 点选历史版本就能找到以前的版本下载了 方法二: 1.用360软体管家下载安装豌豆荚2.54版本 2.用豌豆荚搜寻“微信”点选右下角的更多微信版本 3.这里能找到不同网站的所有历史版本下载

android 怎么封装titlebar

Android标题栏新增控制元件及Button控制元件背景颜色的设定一、Android中标题栏新增按现在很多的Android程式都在标题栏上都显示了一些按钮和标题,如下图:下面通过例项来看一下如何实现。1、在layout下建立一个titlebtn.xml档案,内容如下:在创

android sharesdk登陆怎么封装

(1)Activity或Fragment实现ShareCallback 回拨方法

回拨方法如下:

public interface ShareCallback {

分享成功

void shareSuess(Platform platform, int i, HashMapString, Object hashMap);

分享失败

void shareError(Platform platform, int i, Throwable throwable);

取消分享

void shareCancel(Platform platform, int i);

}

android怎么封装json资料

public static String getJsonStr(){

try {

JSONObject object1 = new JSONObject();

android studio pickerview 资料怎么封装

封装就是资料打包,拆包就是解包。1般传送方把需要传送的资料打包发出去后,接收方收到包后解包解出资料。

android怎么封装ui元件库

封装就是要主要不要和任务相关,提供的介面要尽量合理和便捷使用.

android android怎么将布局档案封装

要看你的view是一个dialog还是一个普通的view.

单纯的渲染apple.xml的话,用inflater就可以。但是你要显示的话,要么是在一个dialog上,要么是新增的activity的view中,这个时候你要有一个viewgroup作为你的apple view的parent

关于androidjni和Androidjni编程的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

标签列表