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.pswp.cn/news/395404.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/395404.shtml
英文地址,請注明出處:http://en.pswp.cn/news/395404.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

signature=f7a4b29b93ef2b36608792fdef7f454a,Embedding of image authentication signatures

摘要&#xff1a;A method (), an apparatus, a computer readable medium and use of said method for authenticating an audio-visual signal (), such as a digital image or video, are disclosed. A signature is derived from all image regions, including areas with …

glob

主要是用來在匹配文件&#xff0c;相當shell中用通配符匹配. 用法: glob.glob(pathname) # 返回匹配的文件作為一個列表返回 glob.iglob(pathname) # 匹配到的文件名&#xff0c;返回一個迭代器 ps: pathname是路徑, 可以是絕對和相對路徑 匹配當前目錄下有一個數字開頭…

構建微服務:Spring boot 入門篇

Spring官方網站本身使用Spring框架開發&#xff0c;隨著功能以及業務邏輯的日益復雜&#xff0c;應用伴隨著大量的XML配置文件以及復雜的Bean依賴關系。隨著Spring 3.0的發布&#xff0c;Spring IO團隊逐漸開始擺脫XML配置文件&#xff0c;并且在開發過程中大量使用“約定優先配…

img 加載 svg占位符_如何使用SVG作為占位符以及其他圖像加載技術

img 加載 svg占位符by Jos M. Prez由JosM.Prez 如何使用SVG作為占位符以及其他圖像加載技術 (How to use SVG as a Placeholder, and Other Image Loading Techniques) I’m passionate about image performance optimisation and making images load fast on the web. One of…

hibernate 注解

參考鏈接地址&#xff1a;https://blog.csdn.net/wx5040257/article/details/78697119 主鍵生成策略:https://www.cnblogs.com/ph123/p/5692194.html 注解轉載于:https://www.cnblogs.com/wangxuekui/p/10287647.html

iOS - UIScrollView

前言 NS_CLASS_AVAILABLE_IOS(2_0) interface UIScrollView : UIView <NSCoding>available(iOS 2.0, *) public class UIScrollView : UIView, NSCoding 移動設備的屏幕大小是極其有限的&#xff0c;因此直接展示在用戶眼前的內容也相當有限。當展示的內容較多&…

機器學習的展望

現階段越來越多的投入到機器學習的熱潮中來&#xff0c;有的人很是興奮&#xff0c;認為這是一場新和革命&#xff0c;一場終極人工智能來臨的前夜。也有人表示悲觀&#xff0c;認為不僅機器學習不代表終極人工智能&#xff0c; 也還非常不成熟。 大量的新生代投入到這個領域&a…

BZOJ3453 XLkxc(拉格朗日插值)

顯然f(i)是一個k2項式&#xff0c;g(x)是f(i)的前綴和&#xff0c;則顯然其是k3項式&#xff0c;插值即可。最后要求的東西大膽猜想是個k4項式繼續插值就做完了。注意2p>maxint…… #include<iostream> #include<cstdio> #include<cmath> #include<cs…

電郵地址_利用這些簡單的技巧來充分利用電子郵件的強大功能

電郵地址Let’s talk about some email features that are surprisingly under-used, and that can really benefit you — if you know how to use them. This article is suitable for both users and developers who want to become email Jedi.讓我們討論一些電子郵件功能&…

inputstream重新賦值之前需要close嗎_變量提升真的搞懂了嗎?打臉的一道題

變量提升真的搞懂了嗎&#xff1f;打臉的一道題我們知道JS代碼在執行之前&#xff0c;會做一系列的事情&#xff0c;其中就包括變量提升&#xff0c;原本以為把變量提升搞懂的我&#xff08;因為這兩天一直在研究變量提升&#xff0c;自我感覺已經很良好了&#xff0c;哈哈哈&a…

html5語義化 兼容,HTML5語義化標簽,兼容性問題

HTML5不僅僅作為HTML標記語言的一個最新版本&#xff0c;更重要的是它制定了web應用開發的一系列標準&#xff0c;成為第一個將web做為應用開發平臺的HTML語言。HTML5定義了一系列的新元素&#xff0c;如新語義化標簽&#xff0c;智能表單&#xff0c;多媒體標簽等&#xff0c;…

Swift之 vm10虛擬機安裝Mac OS X10.10教程

VM10裝Mac OS X 10.9.3及更新到Mac OS X 10.10,讓你的windows也能玩Swift 。 近期WWDC放出終極大招——新的編程語言Swift(雨燕),導致一大波程序猿的圍觀和躍躍欲試。當然了,工欲善其事,必先利其器,所以對于那些沒有Mac又想要嘗鮮的小伙伴肯定非常為難。可是&#xff0c;請放…

如何使用json開發web_如何通過使用JSON Web令牌簡化應用程序的身份驗證

如何使用json開發webby Sudheesh Shetty由Sudheesh Shetty 如何通過使用JSON Web令牌簡化應用程序的身份驗證 (How to simplify your app’s authentication by using JSON Web Token) Every application we come across today implements security measures so that the user…

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次可能的最優解。所以我們只要把這兩個數組做比較…

html自動按鍵,VBS腳本和HTML DOM自動操作網頁

本來是想通過JS實現對其他頁面的控制&#xff0c;發現跨域無法獲取頁面DOM來操作。接著考慮bat&#xff0c;發現也實現不了&#xff0c;于是想到vbs。vbs還是很強大啊&#xff0c;病毒之類很多都是vbs腳本啊。vbs打開瀏覽器&#xff0c;然后通過dom來操作頁面&#xff0c;可以實…

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…

advanced east_SpriteKit Advanced —如何構建2,5D游戲(第二部分)

advanced eastby Luke Konior盧克科尼爾(Luke Konior) SpriteKit Advanced —如何構建2,5D游戲(第二部分) (SpriteKit Advanced — How to build a 2,5D game (Part II)) 介紹 (Intro) This article shows how to write basic shaders in the SpriteKit. It’s split into two…