Android JNI调用概要

2023-05-16

一、Java调C

  1. 编写Native方法。
  2. 使用javah命令生成.h头文件。
  3. 复制.h头文件到CPP工程中。
  4. 复制jni_md.h和jni.h到CPP工程中。
  5. 实现.h头文件中生成的。
  6. 生成dll文件。

C的函数名称:Java_包名_方法名称。

1、java:Test

public class Test {
    public static void main(String[] args) {
        System.out.println(Test.class.getName());
    }

    public static native  void getStringFormC();
}

2、javah:Test.h

命令:javah Test

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Test */

#ifndef _Included_Test
#define _Included_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Test
 * Method:    getStringFormC
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_Test_getStringFormC
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

3、c实现:Test.cpp

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class Test */

#ifndef _Included_Test
#define _Included_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Test
 * Method:    getStringFormC
 * Signature: ()V
 */
JNIEXPORT jstring JNICALL Java_Test_getStringFormC(JNIEnv* env, jclass) {
  //将C的字符串转为JAVA的字符串
  return env -> NewStringUTF("C string");
}

#ifdef __cplusplus
}
#endif
#endif

二、Android JNI

1、Android Studio创建C++项目

2、app/src/main/cpp/CMakeLists.txt: 

# 版本号
cmake_minimum_required(VERSION 3.10.2)

# 项目名称,没有实际意义,可以选填
project("testc1")

# 添加写的cpp项目注意需要在追加在最后面,有先后顺序的
add_library(
		# 参数1:依赖库的名称,仅此一个,在System.loadLibrary("testc1")使用
        testc1

        # 参数2:
        SHARED

        # 参数3:生成的或者自己写的cpp需要加在后面,不能插入到前两个参数中
        native-lib.cpp)


find_library( 
        log-lib

        log)

target_link_libraries( 
        testc1
)

关于CMake 使用:https://mp.weixin.qq.com/s/XFwHkg89qifyUqlSOSJUdw

3、app/src/main/cpp/native-lib.cpp

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_simple_testc1_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */) {
	// 将C的字符串转为JAVA的字符串
    char* hello = "Hello from C++666";
    return env->NewStringUTF(hello);
}

4、app/src/main/java/com/simple/testc1/MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Example of a call to a native method
        binding.sampleText.text = stringFromJNI()
    }

    /**
     * A native method that is implemented by the 'testc1' native library,
     * which is packaged with this application.
     */
    private external fun stringFromJNI(): String

    companion object {
        // Used to load the 'testc1' library on application startup.
        init {
            System.loadLibrary("testc1")
        }
    }
}

效果图:

三、JNIEnv调用分析

  • 在C++中JNIEnv是一个结构体_JNIEnv
  • 在C语言中JNIEnv是一个结构体指针JNINativeInterface*
struct _JNIEnv;
struct _JavaVM;
typedef const struct JNINativeInterface* C_JNIEnv;

#if defined(__cplusplus)
//在C++中JNIEnv是一个结构体_JNIEnv
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
//在C语言中JNIEnv是一个结构体指针JNINativeInterface*
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif

env->NewStringUTF(hello):

C++:

struct _JNIEnv {
   const struct JNINativeInterface* functions;
#if defined(__cplusplus)

jstring NewStringUTF(const char* bytes){ 
  //参数this,表示上下文环境即:env 
  return functions->NewStringUTF(this, bytes); 
}

#endif

调用functions的NewStringUTF,即调用C语言中的NINativeInterface*

C语言:

struct JNINativeInterface {
  //参数1:JNIEnv指针,参数2:字符串
  jstring   (*NewStringUTF)(JNIEnv*, const char*);
}

关于JNIEnv详细解析参考: Android JNI 之 JNIEnv 解析

四、JNI引用变量

引用类型:局部引用和全局引用。

1、局部引用

  • 访问一个很大的JAVA对象,使用完成之后进行复杂的耗时操作。
  • 创建了大量的局部引用,占用的内存太多,而这些局部操作和后面的引用没有关联性。

通过DeleteLocalRef手动释放。

env -> DeleteLocalRef(obj)

2、全局引用

全局共享:创建,获得,释放。三步走,共享可以跨线程,在任意地方调用。

env -> DeleteGlobalRef(obj)

源码:

void DeleteGlobalRef(jobject gref) {
    functions->DeleteGlobalRef(this,gref);
}
void DeleteLocalRef(jobject obj) {
    functions->DeleteLocalRef(this, obj);
}

3、弱全局引用

  • 节省内存,在内存不足的时候释放所引用的对象。
  • 可以引用一个不常用的对象,如果内NULL,临时创建。

源码:

jweak NewWeakGlobalRef(jobject obj) {
    return functions->NewWeakGlobalRef(this,obj);
}
void DeleteWeakGlobalRef(jweak ref) {
    functions->DeleteWeakGlobalRef(this,ref);
}

五、JNI异常处理

  • 保证java可以运行。
  • 保证后面的C代码可以继续运行。

示例:

jthrowable exception = env->ExceptionOccurred();
if (exception != NULL) {
    //可以让java代码继续运行,请空异常信息
    env->ExceptionClear();
}

源码:

jthrowable ExceptionOccurred() {
    return functions->ExceptionOccurred(this);
}
void ExceptionDescribe() {
    functions->ExceptionDescribe(this);
}
void ExceptionClear() {
    functions->ExceptionClear(this);
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android JNI调用概要 的相关文章

  • 通过数据绑定将字符串传递到包含的布局不起作用

    我正在尝试使用 Android 数据绑定功能将一个简单的字符串从我的主布局传递到布局 它编译得很好 但传递给包含的值实际上并未传递 即 它没有出现在我的布局中
  • Android 主机意图过滤器通配符

    是否可以在 android host 属性上使用通配符 就像是 android host site com android pathPattern android pathPrefix m android scheme http gt Or
  • 在 Android 中创建和使用 9 补丁图像

    我最近听说了 9 补丁图像 我知道它是 9 平铺的并且是可拉伸的 我想了解更多 如何创建 9 块图像 有什么工具吗 我可以通过 AndroidSDK 或代码创建它吗 9 patch 相对于普通 png 的主要优点 它是否可以根据屏幕动态 自
  • 单击 RecyclerView 内的 ImageView 时更改图像资源

    每当我单击它时 单击图像 而不是项目 我都会尝试更改回收器视图内特定位置的设备图像资源 我尝试将 setOnClickListener 放入 onBindViewHolder 方法中 但只有最后一个项目受到影响 这是我的回收者视图 http
  • 显示警报或收到通知时的视图

    我正在关注this http tokudu com 2010 how to implement push notifications for android 显示的教程通知 on an 安卓设备 当我在设备上运行该应用程序时 状态栏上会出现
  • 我可以在 firebase android 中加载另一个用户个人资料图像吗?

    如果我有其他用户的电子邮件但我以其他用户身份登录 我是否可以加载其他用户的个人资料图像 如果您使用 Firebase Storage 那么从技术上讲是的 它只是一个您可以从中检索任何文件的文件系统 如果不伪造您的应用程序 获取 api 密钥
  • 如何将 EditText 传递给另一个活动?

    Intent intent new Intent this Name class intent putExtra key et getText toString startActivity intent Intent intent getI
  • Google Firebase - 如何删除崩溃报告?

    我最终失明了吗 还是没有明显的方法可以通过 Google Firebase Web 控制台删除 Firebase 崩溃报告 我的 Android 应用程序已成功记录报告 但现在出现大量 开发崩溃 占用了我在控制台中的大部分视图 这使得找到实
  • 如何将画廊意图中的“打开”更改为“完成”?

    我使用以下意图打开画廊来选择多个图像和视频 Intent intent new Intent intent setType image video intent putExtra Intent EXTRA ALLOW MULTIPLE tr
  • 如何使用闹钟音量和 setAudioAttributes 来播放铃声?

    所以我正在尝试了解音频属性 这是我到目前为止所拥有的 alarm getSound will return a proper URI to pick a ringtone Ringtone tone RingtoneManager getR
  • React Native Android 发布 apk 是调试,而不是发布

    我有一个现有的 Android 应用程序 我已根据以下内容将 React Native v0 30 活动添加到项目中docs http facebook github io react native releases next docs i
  • 如何在 Android 上创建 YouTube 的双击手势?

    我在 Android 上有 exoplayer 的应用程序 我已经创建了 youtube双击手势用动画向前或向后跳跃 10 秒 如何在双击时创建具有波纹效果的半圆 像这样 这个怎么做 我也想实现这样的功能 所以我自己编写了它来 复制 You
  • 如何从android获取应用程序安装时间

    我尝试了一些方法 但没有成功 请帮助我 PackageManager pm context getPackageManager ApplicationInfo appInfo pm getApplicationInfo app packag
  • 加快 ImageView 中的缩放功能

    我目前正在处理非常大的图像 7 10mb 由于多种原因无法调整大小或压缩 现在 我们的想法是在自定义 ImageView 中显示它们 使用户能够进行双击缩放 捏合缩放等 我使用这个库来完成这项工作 https github com Mike
  • Android 改变 ImageView / Bitmap 的颜色

    我需要找到一种方法来改变 Android 中位图的颜色 我需要在我的应用程序中平滑地替换 更改椭圆形图像的颜色 具体取决于int价值 我需要类似的东西myValue 5比改变我的图像的颜色RED and if myValue 322将颜色更
  • 通过列表视图检查动态生成的复选框时遇到问题

    我知道其他成员已经提出了这个问题 一些成员也给出了解决方案 但问题是我没有找到任何适合我的应用程序的解决方案 我正在创建一个应用程序 其中我有一个屏幕 它将显示动态列表视图 其中包含列表项 复选框和三个文本视图 一个用于候选人姓名 另外两个
  • 内部存储的安全性如何?

    我需要的 对于 Android 我需要永久保存数据 但也能够编辑 并且显然是读取 它 用户不应访问此数据 它可以包含诸如高分之类的内容 用户不得对其进行编辑 我的问题 我会 并且已经 使用过Internal Storage 但我不确定它实际
  • 如何获取android手机型号、版本、sdk详细信息?

    如何获取android手机型号 版本 sdk详细信息 首先 看看 android sdk 页面上的这些 Build 类 http developer android com reference android os Build html h
  • 通过powershell运行ADB命令

    所以我尝试通过 powershell 脚本运行一些 ADB 命令 这是我正在尝试做的一个简单示例 adb shell echo in adb shell su root echo you are now root ls cd data da
  • 如何以编程方式创建活动转换?

    我想以编程方式创建一个动画 以从触摸屏点启动具有缩放效果的活动 接下来我模拟缩放输入效果

随机推荐