JNI通过线程c回调java层的函数

1、参看博客:http://www.jianshu.com/p/e576c7e1c403

Android JNI 篇 - JNI回调的三种方法(精华篇)

2、参看博客: 

JNI层线程回调Java函数关键点及示例

http://blog.csdn.net/fu_shuwu/article/details/41121741

 3 http://blog.csdn.net/u010402982/article/details/48199487

核心的关键点:

三、本地线程中调用java对象

问题1:

JNIEnv是一个线程相关的变量

JNIEnv 对于每个 thread 而言是唯一的

JNIEnv *env指针不可以为多个线程共用

解决办法:

但是java虚拟机的JavaVM指针是整个jvm公用的,我们可以通过JavaVM来得到当前线程的JNIEnv指针.

可以使用javaAttachThread保证取得当前线程的Jni环境变量

static JavaVM *gs_jvm=NULL;

gs_jvm->AttachCurrentThread((void **)&env, NULL);//附加当前线程到一个Java虚拟机

jclass cls = env->GetObjectClass(gs_object);

jfieldID fieldPtr = env->GetFieldID(cls,"value","I");

问题2:

不能直接保存一个线程中的jobject指针到全局变量中,然后在另外一个线程中使用它。

解决办法:

用env->NewGlobalRef创建一个全局变量,将传入的obj(局部变量)保存到全局变量中,其他线程可以使用这个全局变量来操纵这个java对象

注意:若不是一个 jobject,则不需要这么做。如:

jclass 是由 jobject public 继承而来的子类,所以它当然是一个 jobject,需要创建一个 global reference 以便日后使用。

而 jmethodID/jfieldID 与 jobject 没有继承关系,它不是一个 jobject,只是个整数,所以不存在被释放与否的问题,可保存后直接使用。

 

总结:创建两个全局的变量一个是JavaVM 虚拟机环境jvm

另外一个全局变量是jobj对象

然后创建一个线程,使用全局的jvm获得与该线程一一对应的env,通过env和全局的jobj对象,创建java层的对象,调用java层的方法,最近将线程环境关闭。

 

我们来看下程序的框架:

我们来看下程序的代码:

package im.weiyuan.com.jni;public class Sdk {static {System.loadLibrary("hello");}public Sdk() {}//单例private static class SdkHodler {static Sdk instance = new Sdk();}public static Sdk getInstance() {return SdkHodler.instance;}//回调到各个线程public interface OnSubProgressListener {public int onProgressChange(long total, long already);};
//c层回调上来的方法public int onProgressCallBack(long total, long already) {//自行执行回调后的操作System.out.println("total:"+total);System.out.println("already:"+already);return 1;}//调到C层的方法public native void nativeDownload();}

然后

(一)   第二步:make project一下,目的就是编译成对应的class文件。然后根据生成的class文件,利用javah生成对应的 .h头文件。

 

(一)   第三步:

Cmd终端进入到你新建的android工程的src/main目录下:我的目录是:

F:\JNI\app\src\main

执行命令:

Javah -d jni -classpath D:\android_sdk_ndk\sdk\platforms\android-21\android.jar;..\..\build\intermediates\classes\debug im.weiyuan.com.jni.Sdk

其中: D:\android_sdk_ndk\sdk\是你sdk的路径 

 im.weiyuan.com.jni.Sdk是你对应的

就是你声明的native函数所在的包名加上类名。

就会发现在main目录下多了一个jni文件夹,里面有生成好的头文件:

 

在这个头文件中就自动帮助我们生成了函数的声明

第五步:

在jni目录下新建一个 .c文件。来实现头文件里面声明的方法。我的叫im_weiyuan_com_jni_Sdk.c

我们来看下程序的代码:

//
// Created by wei.yuan on 2017/6/13.
//
#include <jni.h>
#include <string.h>
#include <pthread.h>
#include "im_weiyuan_com_jni_Sdk.h"
#include "im_weiyuan_com_jni_Sdk_OnSubProgressListener.h"
#include "im_weiyuan_com_jni_Sdk_SdkHodler.h"
JavaVM *g_VM;
jobject g_obj;
#include <jni.h>
#include <string.h>
#include <android/log.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <assert.h>
#include <android\log.h>
#include <errno.h>
#include <pthread.h>static  void* native_thread_exec(void* arg){JNIEnv *env;int mNeedDetach = -1;//获取当前native线程是否有没有被附加到jvm环境中int getEnvStat = (*g_VM)->GetEnv(g_VM, (void **) &env,JNI_VERSION_1_6);if (getEnvStat == JNI_EDETACHED) {//如果没有, 主动附加到jvm环境中,获取到envif ((*g_VM)->AttachCurrentThread(g_VM, &env, NULL) != 0) {return;}mNeedDetach = JNI_TRUE;}//通过全局变量g_obj 获取到要回调的类jclass javaClass = (*env)->GetObjectClass(env, g_obj);if (javaClass == 0) {// LOGI("Unable to find class");(*g_VM)->DetachCurrentThread(g_VM);return;}//获取要回调的方法IDjmethodID javaCallbackId = (*env)->GetMethodID(env, javaClass,"onProgressCallBack", "(JJ)I");if (javaCallbackId == NULL) {//LOGI("Unable to find method:onProgressCallBack");return;}//执行回调(*env)->CallIntMethod(env, g_obj, javaCallbackId,100,100);//释放当前线程if(mNeedDetach) {(*g_VM)->DetachCurrentThread(g_VM);}


//释放你的全局引用的接口,生命周期自己把控
(*env)->DeleteGlobalRef(env, g_obj);
g_obj = NULL;
    env = NULL;

} JNIEXPORT
void JNICALL Java_im_weiyuan_com_jni_Sdk_nativeDownload (JNIEnv * env , jobject thiz){//JavaVM是虚拟机在JNI中的表示,等下再其他线程回调java层需要用到(*env)->GetJavaVM(env, &g_VM);// 生成一个全局引用保留下来,以便回调g_obj = (*env)->NewGlobalRef(env, thiz);// 此处使用c语言开启一个线程,进行回调,这时候java层就不会阻塞,只是在等待回调 pthread_t thread_id;if(( pthread_create(&thread_id,NULL, native_thread_exec,NULL))!=0){return ;}return; }

其中:

JNIEXPORT void JNICALL Java_im_weiyuan_com_jni_Sdk_nativeDownload
(JNIEnv * env , jobject thiz)就是在im_weiyuan_com_jni_Sdk.h头文件中系统自动生成的

(一)   第五步:配置ndk的路径

在 local.properties 文件中设置ndk的路径:

 

sdk.dir=D\:\\android_sdk_ndk\\sdk
ndk.dir=D\:\\android_sdk_ndk\\android-ndk-r10e

 

 

(一)   在gradle.propertes中添加

android.useDeprecatedNdk=true

http://stackoverflow.com/questions/31979965/after-updating-android-studio-to-version-1-3-0-i-am-getting-ndk-integration-is

 

 

在app目录下的 build.gradle中设置库文件名(生成的so文件名):

 

找到 defaultConfig 这项,在里面添加如下内容:

        ndk{

            moduleName "hello"  //设置库(so)文件名称

            abiFilters "armeabi", "armeabi-v7a", "x86" 

        }

这里    hello必须和 

 static {

        System.loadLibrary("hello");

}中的名字是对应的,abiFilters是指定生成那种平台下的so库,对应于eclipse中的Aplication.mk文件中的内容。编译,并运行。界面上就会显示从native方法传过来的值。

在c代码中
  "onProgressCallBack", "(JJ)I"
这里调用上层java函数的时候,使用到了函数的签名:
如何得到函数的签名了:

如何查看函数的签名:

如果当前的工程存放的目录在F盘下的JNI目录:

进入到工程的F:\JNI\app\build\intermediates\classes\debug 目录下

执行命令:

Javap  -s  im.weiyuan.com.jni.Sdk

 

其中im.weiyuan.com.jni是包名,Sdk是类名

F:\JNI\app\build\intermediates\classes\debug> javap -s im.weiyuan.com.jni.Sdk

Compiled from "Sdk.java"

public class im.weiyuan.com.jni.Sdk {

  public im.weiyuan.com.jni.Sdk();

    descriptor: ()V

 

  public static im.weiyuan.com.jni.Sdk getInstance();

    descriptor: ()Lim/weiyuan/com/jni/Sdk;

 

  public int onProgressCallBack(long, long);

    descriptor: (JJ)I

 

  public native void nativeDownload();

    descriptor: ()V

 

  static {};

    descriptor: ()V

}

 

在activity中我们可以调用native函数的代码:

package im.weiyuan.com.jni;import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//调用native的方法
        Sdk.getInstance().nativeDownload();}
}

我们来看下程序的运行结果:

06-13 15:38:40.070 14935-15032/? I/System.out: total:100

android studio 的代码地址:

 http://download.csdn.net/detail/jksfkdjksdfjkjk/9869331

生成的so的目录如下所示:

 

转载于:https://www.cnblogs.com/kebibuluan/p/7001705.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/395404.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

构建微服务:Spring boot 入门篇

Spring官方网站本身使用Spring框架开发&#xff0c;随着功能以及业务逻辑的日益复杂&#xff0c;应用伴随着大量的XML配置文件以及复杂的Bean依赖关系。随着Spring 3.0的发布&#xff0c;Spring IO团队逐渐开始摆脱XML配置文件&#xff0c;并且在开发过程中大量使用“约定优先配…

iOS - UIScrollView

前言 NS_CLASS_AVAILABLE_IOS(2_0) interface UIScrollView : UIView <NSCoding>available(iOS 2.0, *) public class UIScrollView : UIView, NSCoding 移动设备的屏幕大小是极其有限的&#xff0c;因此直接展示在用户眼前的内容也相当有限。当展示的内容较多&…

inputstream重新赋值之前需要close吗_变量提升真的搞懂了吗?打脸的一道题

变量提升真的搞懂了吗&#xff1f;打脸的一道题我们知道JS代码在执行之前&#xff0c;会做一系列的事情&#xff0c;其中就包括变量提升&#xff0c;原本以为把变量提升搞懂的我&#xff08;因为这两天一直在研究变量提升&#xff0c;自我感觉已经很良好了&#xff0c;哈哈哈&a…

Swift之 vm10虚拟机安装Mac OS X10.10教程

VM10装Mac OS X 10.9.3及更新到Mac OS X 10.10,让你的windows也能玩Swift 。 近期WWDC放出终极大招——新的编程语言Swift(雨燕),导致一大波程序猿的围观和跃跃欲试。当然了,工欲善其事,必先利其器,所以对于那些没有Mac又想要尝鲜的小伙伴肯定非常为难。可是&#xff0c;请放…

c++ 实现录音并且指定到文件_通话自动录音,留下美好回忆,记录完整录音证据...

手机通话&#xff0c;如果自动录音多好&#xff0c;许多人与我一样抱有这个想法。记得华为Android版本5.0时代&#xff0c;手机没有自动录音功能&#xff0c;我一直到网上下载自动通话录音软件&#xff0c;有时甚至是下载ROOT版的带自动通话功能的EMUI版本进行刷机安装。那个时…

2639-Bone Collector II (01背包之第k优解)

题目链接&#xff1a; http://acm.hdu.edu.cn/showproblem.php?pid2639 求第k优解的关键代码&#xff1a; 用两个数组记录两种状态&#xff08;选择或不选择&#xff09;&#xff0c;并且只要记录前k次。在这两个数组中都是前k次可能的最优解。所以我们只要把这两个数组做比较…

opencv在同一窗口打印多张图片

首先&#xff0c;由于cv2处理的图片是通过ndarray的格式操作的&#xff0c;也就是说通过array的拼接就可以实现图片的拼接&#xff0c;那么之后就可以通过简单的imshow将合并的图片打印从而达到在一个窗口中显示多张图片的目的。 import cv2 import numpy as npimg1 cv2.imrea…

dj打碟怎么学_学DJ打碟 - Rane声卡连接

上一篇内容中&#xff0c;老师讲过在学DJ打碟的时候&#xff0c;是离不开对软件方面的操作&#xff0c;其实每一个学习过程&#xff0c;当你学会之后&#xff0c;在“回头看”的时候&#xff0c;都会觉得&#xff1a;原来学DJ打碟这么简单啊&#xff0c;这就是已经学习过的人会…

微信企业号第三方应用开发[一]——创建套件

注&#xff1a;文中绿色部分为摘自微信官方文档 第三方应用提供给企业的是一个应用&#xff0c;但是应用必须在套件下创建&#xff0c;所以第一步是要创建套件。 注册成为应用提供商&#xff0c;必须输入以下信息&#xff1a; 信息项要求及说明企业Logo应用提供商的企业Logo&am…

html原生上传,一个基于HTML5及原生JS的文件上传组件--JohnUploader

运行效果图一、组件介绍基本特点基于HTML5的FileReader和FormData可以完成多文件选择&#xff0c;并预览完成文件的异步上传原生XHR对象&#xff0c;适配多浏览器代码class JohnUploader{url;fileField;vollay;/**** param url 文件上传的地址* param fileField 一个"文件…

微信企业号第三方应用开发[二]——创建应用

在应用套件里添加应用 当你创建完应用套件后&#xff0c;需要在套件配置应用&#xff0c;应用的信息填写如下。 基本信息&#xff1a; 信息项要求及说明应用Logo应用的Logo&#xff0c;小于2M&#xff0c;640*640&#xff0c;在授权页会被用于展示。应用名称应用的名称&#xf…

jQ效果:简单的手风琴效果

实现效果如图所示&#xff1a; html结构&#xff1a; <div class"item_box box10"><div class"item_box_wp"><div class"voice_2"><ul><li class"li1" id"li1"><div class"fold"…

golang 日志分析_容器日志采集利器:Filebeat深度剖析与实践

在云原生时代和容器化浪潮中&#xff0c;容器的日志采集是一个看起来不起眼却又无法忽视的重要议题。对于容器日志采集我们常用的工具有filebeat和fluentd&#xff0c;两者对比各有优劣&#xff0c;相比基于ruby的fluentd&#xff0c;考虑到可定制性&#xff0c;我们一般默认选…

java ldap userpassword 解密_Spring Boot中使用LDAP来统一管理用户信息

LDAP简介LDAP(轻量级目录访问协议&#xff0c;Lightweight Directory Access Protocol)是实现提供被称为目录服务的信息服务。目录服务是一种特殊的数据库系统&#xff0c;其专门针对读取&#xff0c;浏览和搜索操作进行了特定的优化。目录一般用来包含描述性的&#xff0c;基于…

unity中怎么做河流_【干货】工作中怎么做工业设计的?(一)

最近在找工作&#xff0c;一直在看招聘信息。看到工业设计工资还是蛮高的。应届毕业生一般是4-6K&#xff0c;1-3年工作经验是6-8K&#xff0c;3年以后的差不多是8K以上了。我没有嫉妒羡慕恨&#xff0c;发誓&#xff0c;真的没有。工业设计已经被重视&#xff0c;未来的道路会…

[易学易懂系列|golang语言|零基础|快速入门|(一)]

golang编程语言&#xff0c;是google推出的一门语言。 主要应用在系统编程和高性能服务器编程&#xff0c;有广大的市场前景&#xff0c;目前整个生态也越来越强大&#xff0c;未来可能在企业应用和人工智能等领域占有越来越重要的地位。 本文章是【易学易懂系列|编程语言入门】…

spi收发时的寄存器sr不变_「正点原子Linux连载」第二十七章SPI实验(二)

1)实验平台&#xff1a;正点原子Linux开发板2)摘自《正点原子I.MX6U嵌入式Linux驱动开发指南》关注官方微信号公众号&#xff0c;获取更多资料&#xff1a;正点原子文件bsp_spi.c中有两个函数&#xff1a;spi_init和spich0_readwrite_byte&#xff0c;函数spi_init是SPI初始化函…

[JSOI2018]潜入行动

题解 一道思路不难但是写起来很麻烦的树形背包 我们发现每个节点有很多信息需要保留 所以就暴力的设\(f[u][j][0/1][0/1]\)表示点u的子树分配了j个监察器,点u有没有被控制,点u放没放监察器 然后就分四种情况暴力讨论就好了 注意背包的时候要卡常数 代码 #include<cstdio>…

css。元素样式、边框样式

1.外边距  margin 缩写形式&#xff1a; margin&#xff1a;上边距  右边距  下边距  左边距 margin&#xff1a;上下边距  左右边距 margin&#xff1a;上边距  左右边距  下边距 2.内边距  padding 缩写形式&#xff1a; padding&#xff1a;上边距  右边距…

C# 动态创建数据库三(MySQL)

前面有说明使用EF动态新建数据库与表&#xff0c;数据库使用的是SQL SERVER2008的&#xff0c;在使用MYSQL的时候还是有所不同 一、添加 EntityFramework.dll &#xff0c;System.Data.Entity.dll &#xff0c;MySql.Data, MySql.Data.Entity.EF6 注意&#xff1a;Entity Frame…