深入理解Android(4)——理解Android中的JNI(下)
在前面文章中简单介绍了JNI,这一篇文章来简单看一下jni.h中定义的一些常用方法,来实现通过C++调用Android中的Java代码。
转载请说明出处:http://blog.csdn.net/dawanganban
一、两个参数的介绍
在前面的代码中我们会遇到两个参数,下面对这两个参数做一解释
1、JNIEnv是指向可用JNI函数表的接口指针,C代码中JNIEnv是指向JNINativeInterface结构的指针,在C语言中JNIEnv必须作为第一个参数传入每一个JNI函数的调用者,如:
(*env)->NewStringUTF(env, "helloworld");
在C++中,JNIEnv是C++类的实例,JNI函数以成员函数形式存在,所以在JNI环境中,无序传入该参数,如:
env->NetStringUTF("helloworld");
2、jobject是一个指向java对象的引用,如果本地方法是一个静态方法,则是指向类字节码文件的class对象。
二、JNI数据类型
1、基本类型映射
从上表中可以看出,Java的数据类型和C++的基本数据类型有一个映射关系,我们在使用JNI的时候可以直接使用Natvie Type来操作Native层的数据,这样就不用记忆复杂的映射关系了,从变量的名字上我们可以看到在Java的基本数据类型前面加一个字母‘j'就是对应的C++的Native类型。
2、引用类型映射
与基本类型不同的是,引用类型对原生的方法是不透明的(不能直接使用和修改),JNI提供了与这些引用类型密切相关的一组API ,这些API通过JNIEnv接口指针提供给原生函数。
我们在jni.h中可以看到上面类型的定义:
class _jobject {};
class _jclass : public _jobject {};
class _jthrowable : public _jobject {};
class _jstring : public _jobject {};
class _jarray : public _jobject {};
class _jbooleanArray : public _jarray {};
class _jbyteArray : public _jarray {};
class _jcharArray : public _jarray {};
class _jshortArray : public _jarray {};
class _jintArray : public _jarray {};
class _jlongArray : public _jarray {};
class _jfloatArray : public _jarray {};
class _jdoubleArray : public _jarray {};
class _jobjectArray : public _jarray {};
typedef _jobject *jobject;
typedef _jclass *jclass;
typedef _jthrowable *jthrowable;
typedef _jstring *jstring;
typedef _jarray *jarray;
typedef _jbooleanArray *jbooleanArray;
typedef _jbyteArray *jbyteArray;
typedef _jcharArray *jcharArray;
typedef _jshortArray *jshortArray;
typedef _jintArray *jintArray;
typedef _jlongArray *jlongArray;
typedef _jfloatArray *jfloatArray;
typedef _jdoubleArray *jdoubleArray;
typedef _jobjectArray *jobjectArray;
这些类的设计和Java一样,都继承自一个名为_jobject的父类。
三、对引用类型操作的例子
package com.example.test; import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast; import com.example.myfirstjniproj.R; /**
* 阳光小强 http://blog.csdn.net/dawanganban
* @author lixiaoqiang
*
*/
public class MainActivity extends Activity implements OnClickListener{ @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); findViewById(R.id.jni_jstring_button).setOnClickListener(this);
findViewById(R.id.jni_javaArray_button).setOnClickListener(this);
} @Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.jni_jstring_button:
showToast(jniStringTest("input string"));
break;
case R.id.jni_javaArray_button:
int[] array = jniArrayTest();
showToast("arr[1]=" + array[1] + " : arr[2]=" + array[2]);
break;
default:
break;
}
} private void showToast(String content){
Toast.makeText(MainActivity.this, content, Toast.LENGTH_SHORT).show();
} public native String jniStringTest(String str); public native int[] jniArrayTest(); static{
System.loadLibrary("jnitest");
}
}
通过javah生成的头文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_test_MainActivity */ #ifndef _Included_com_example_test_MainActivity
#define _Included_com_example_test_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_test_MainActivity
* Method: jniStringTest
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_test_MainActivity_jniStringTest
(JNIEnv *, jobject, jstring); /*
* Class: com_example_test_MainActivity
* Method: jniArrayTest
* Signature: ()[I
*/
JNIEXPORT jintArray JNICALL Java_com_example_test_MainActivity_jniArrayTest
(JNIEnv *, jobject); #ifdef __cplusplus
}
#endif
#endif
c++实现
#include "com_example_test_MainActivity.h"
#include <stdlib.h>
using namespace std; JNIEXPORT jstring JNICALL Java_com_example_test_MainActivity_jniStringTest
(JNIEnv * env, jobject obj, jstring str){
//将java字符串转成c++字符串
jboolean isCopy;
const char* cstr = env->GetStringUTFChars(str, &isCopy);
//释放原生字符串
env->ReleaseStringUTFChars(str, cstr);
//创建字符串
jstring jstr = env->NewStringUTF("hello world");; return jstr;
} JNIEXPORT jintArray JNICALL Java_com_example_test_MainActivity_jniArrayTest
(JNIEnv * env, jobject obj){
//创建一个10个元素的数组
jintArray intarray = env->NewIntArray(10);
if(0 != intarray){
jint nativeArray[10];
//获取原生的数组
env->GetIntArrayRegion(intarray, 0, 10, nativeArray);
nativeArray[1] = 10;
nativeArray[2] = 20;
//设置改变
env->SetIntArrayRegion(intarray, 0, 10, nativeArray);
}
return intarray;
}
四、访问域和获取ID
Java有两个域:实例域和静态域,每个实例都有自己的实例域副本,而一个类的所有实例共享一个静态域。
JNIEXPORT jstring JNICALL Java_com_example_test_MainActivity_getInstanceField
(JNIEnv * env, jobject obj){
//通过对象获得类
jclass clazz;
clazz = env->GetObjectClass(obj);
//获得实例域Id
jfieldID instanceFieldId;
instanceFieldId = env->GetFieldID(clazz, "instanceField", "Ljava/lang/String");
//获得实例域
jobject instanceField;
instanceField = env->GetObjectField(obj, instanceFieldId);
jstring jstr = env->NewStringUTF("获取成功");
return jstr;
} JNIEXPORT jstring JNICALL Java_com_example_test_MainActivity_getStaticField
(JNIEnv * env, jobject obj){
jclass clazz;
clazz = env->GetObjectClass(obj);
jfieldID staticFieldId;
staticFieldId = env->GetStaticFieldID(clazz, "staticField", "Ljava/lang/String");
jobject staticField;
staticField = env->GetStaticObjectField(clazz, staticFieldId);
jstring jstr = env->NewStringUTF("获取成功");
return jstr;
}
在上面代码中我们看到了“Ljava/lang/String"字符串,这个是获取ID的类型签名,Java的类型签名映射表如下:
五、调用Java中的方法
与上面的域一样,Java中也有两类方法,实例方法和静态方法,JNI提供了两类方法的函数
public native void getInstanceMethod();
public native void getStaticMethod();
public String instanceMethod(){
return "instanceMethod";
}
public static String staticMethod(){
return "staticMethod";
}
JNIEXPORT void JNICALL Java_com_example_test_MainActivity_getInstanceMethod
(JNIEnv * env, jobject obj){
jclass clazz;
clazz = env->GetObjectClass(obj);
jmethodID instanceMethodId;
instanceMethodId = env->GetMethodID(clazz, "instanceMethod", "()Ljava/lang/String");
jstring instanceMethodResult;
instanceMethodResult = env->CallStringMethod(obj, instanceMethodId);
} JNIEXPORT void JNICALL Java_com_example_test_MainActivity_getStaticMethod
(JNIEnv * env, jobject obj){
jclass clazz;
clazz = env->GetObjectClass(obj);
jmethodID staticMethodId;
staticMethodId = env->GetStaticMethodID(clazz, "staticMethod", "()Ljava/lang/String");
jstring staticMethodResult;
staticMethodResult = env->CallStaticStringMethod(clazz, staticMethodId);
}
深入理解Android(4)——理解Android中的JNI(下)的更多相关文章
- Android Studio] Gradle项目中添加JNI生成文件(.so文件)
转:http://blog.csdn.net/qiujuer/article/details/24209457 为了适应潮流使用Android Studio还是有半年多了! 对于从Eclipse迁移项 ...
- [Android][Android Studio] Gradle项目中加入JNI生成文件(.so文件)
版权声明:本文作者:Qiujuer https://github.com/qiujuer; 转载请注明出处,盗版必究! ! ! https://blog.csdn.net/qiujuer/articl ...
- Android Studio Gradle项目中加入JNI so文件
首先在Android Studio(版本号1.2.2)project的app文件夹下创建整个jni文件夹,jni文件夹里写Android.mk.Application.mk以及各类C/C++和汇编源文 ...
- Android:LinearLayout布局中Layout_weight的深刻理解
首先看一下LinearLayout布局中Layout_weight属性的作用:它是用来分配属于空间的一个属性,你可以设置他的权重.很多人不知道剩余空间是个什么概念,下面我先来说说剩余空间. 看下面代码 ...
- Android 深入理解Android中的自定义属性
转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/45022631: 本文出自:[张鸿洋的博客] 1.引言 对于自定义属性,大家肯定 ...
- 深入理解Android(5)——从MediaScanner分析Android中的JNI
前面几篇介绍了Android中的JNI和基本用法,这一篇我们通过分析Android源代码中的JNI实例,来对JNI部分做一个总结. 一.通向两个不同世界的桥梁 在前面我们说过,JNI就像一个桥梁,将J ...
- 深入理解Android(2)——理解Android中的JNI(中)
阳光小强参加了CSDN博客之星评选,如果你觉得阳光小强的博客对你有所帮助,为小强投上一票吧:http://vote.blog.csdn.net/blogstar2014/details?usernam ...
- [译]:Xamarin.Android开发入门——Hello,Android深入理解
返回索引目录 原文链接:Hello, Android_DeepDive. 译文链接:Xamarin.Android开发入门--Hello,Android深入理解 本部分介绍利用Xamarin开发And ...
- Android Gradle 理解
/********************************************************************************* * Android Gradle ...
- Android深入理解Context(二)Activity和Service的Context创建过程
前言 上一篇文章我们学习了Context关联类和Application Context的创建过程,这一篇我们接着来学习Activity和Service的Context创建过程.需要注意的是,本篇的知识 ...
随机推荐
- PHP万能的连接数据库
<?php class DB{ const HOST='127.0.0.1'; const USER='root'; const PASS='root'; const DATA='mooc'; ...
- poj2823/hdu3415 - 数据结构 单调队列
poj2823 题目链接 长度为N的数组,求宽度k的滑动窗口在数组上滑动时窗口内的最大值或最小值 如果用单调队列做,求最小值时,队列应该严格递增的.所以插入时,队尾大于等于插入值的元素都应被舍弃,因为 ...
- ios发布以后关键信息确认与nslog
发布以后信息查看的路径: xcode->window->devices and …->查看如图的log. 通常在发布以后,处于安全和性能的考虑,会禁止打印log:但是在关键的信息需要 ...
- Linux下通过rdesktop连接Windows远程桌面
rdesktop是linux下支持Windows远程桌面连接的客户端程序,在linux系统下可通过它远程访问Windows桌面,支持多种版本.rdesktop是sourceforge下支持GPL协议的 ...
- 关于ios11和Chrome浏览器非HTTPS 对高德定位不支持问题
最近,在开发二维码签到系统时,需要对用户的签到的经纬度进行获取,并且判断签到距离是否在可支持范围内. 使用了高德地图.因为本人最近刚刚入手了一款新的Iphone7里面是最新的ios11系统.发现我的手 ...
- NodeJS学习笔记 (16)子进程-child_process(ok)
原文: https://github.com/chyingp/nodejs-learning-guide/blob/master/README.md 自己的跟进学习: 父进程,子进程,线程之间的关系 ...
- [WC2011]最大XOR和路径(线性基)
P4151 [WC2011]最大XOR和路径 题目描述 XOR(异或)是一种二元逻辑运算,其运算结果当且仅当两个输入的布尔值不相等时才为真,否则为假. XOR 运算的真值表如下( 1 表示真, 0 表 ...
- 百度地图API的使用示例
刚刚工作的时候写过百度地图API文档,那时候没有记录到技术博客里面,今天在群里看见有个姑娘在问这个问题,重温了一遍,这个API还算好用.百度地图API,集成简单好用,全面,兼容问题,文档全面: 官方文 ...
- Unity 获得视频的某一帧,生成缩略图
Unity 并无直接获取视频某一帧图像的API,所以想要生成缩略图就要自己写方法了, 图片和视频都可以用这种方式生成缩略图,另,转载请标明出处,谢谢. using System.Collections ...
- 智能指针的->和 * 重载