欧美三级国产三级日韩三级_亚洲熟妇丰满大屁股熟妇_欧美亚洲成人一区二区三区_国产精品久久久久久模特

AndroidNDK開發(fā)(五)——C代碼回調(diào)Java代碼 - 新聞資訊 - 云南小程序開發(fā)|云南軟件開發(fā)|云南網(wǎng)站建設(shè)-昆明葵宇信息科技有限公司

159-8711-8523

云南網(wǎng)建設(shè)/小程序開發(fā)/軟件開發(fā)

知識

不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價值,我們在追求其視覺表現(xiàn)的同時,更側(cè)重于功能的便捷,營銷的便利,運營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序為后期升級提供便捷的支持!

您當前位置>首頁 » 新聞資訊 » 技術(shù)分享 >

AndroidNDK開發(fā)(五)——C代碼回調(diào)Java代碼

發(fā)表時間:2020-10-19

發(fā)布人:葵宇科技

瀏覽次數(shù):61


        轉(zhuǎn)載請注明出處:http://blog.csdn.net/allen315410/article/details/41862479
        在上篇博客里懂得了Java層是如何傳遞數(shù)據(jù)到C層代碼,并且熟悉了大年夜部分的實際開辟常識,根本上控制這些就可以做一個根本的NDK開辟了,然則光是懂得Java回調(diào)C層的數(shù)據(jù)是不是還不敷啊,推敲問題要推敲可逆性,Java能回調(diào)C,那么C可否反過往返調(diào)Java呢?謎底是肯定可以的,這篇博客就介紹一個C說話若何調(diào)用Java層的代碼。以下是一些問題場景,我們帶著這個問題場景來分析一下實現(xiàn)的過程。
場景1:開辟中C說話層完成了一系列操作后,須要通知Java層代碼此時須要做什么操作。
場景2:大年夜家知道法度榜樣員都是比較懶惰的,Java代碼中封裝了大年夜量的辦法,C法度榜樣員不想反復(fù)寫復(fù)雜的邏輯,這時想經(jīng)由過程C說話回調(diào)應(yīng)用Java層代碼中的辦法。
      解釋native辦法callMethod4已經(jīng)運行成功了。
        好,帶著膳綾擎的場景,我們下面建立一個小的Demo來測驗測驗解決這些營業(yè)場景的問題。
package com.example.ndkcallback;

public class DataProvider {
	/**
	 * C調(diào)用java空辦法
	 */
	public void nullMethod() {
		System.out.println("hello from java");
	}
	/**
	 * C調(diào)用java中的帶兩個int參數(shù)的辦法
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	public int Add(int x, int y) {
		int result = x + y;
		System.out.println("result in java " + result);
		return result;
	}
	/**
	 * C調(diào)用java中參數(shù)為String的辦法
	 * 
	 * @param s
	 */
	public void printString(String s) {
		System.out.println("java " + s);
	}

	// 本處所法
	public native void callMethod1();
	public native void callMethod2();
	public native void callMethod3();

}

編譯頭文件


        在DOS敕令行下,切換到工程目次地點的源碼存放的src目次下,應(yīng)用javah敕令編譯C說話的函數(shù)簽名。并且得留意的是,因為我應(yīng)用的JDK 是1.7版本的,所以必須得切換到工程目次/src目次下履行javah,如不雅大年夜家應(yīng)用的是JDK 1.6或者JDK 1.5,那就切換到工程目次/classes目次,履行javah敕令。
[img]http://img.blog.csdn.net/20141211101935855
留意:應(yīng)用javah敕令時,須要指定-encoding utf-8 參數(shù),防止編譯報亂碼缺點,下面是編譯好的頭文件:

        有了膳綾擎的頭文件,接下來就是最不好搞的C代碼了,按照套路來,起首把膳綾擎編譯好的頭文件剪切到j(luò)ni目次下,在該目次下新建一個Hello.c的C代碼文件,將剛?cè)侨说念^文件的函數(shù)簽名拷貝到Hello.c中應(yīng)用,然后就是起首惹人LOG日記頭文件,定義LOG日記輸入,再然后就是編譯C代碼,如下:
#include<stdio.h>
#include<jni.h>
#include"com_example_ndkcallback_DataProvider.h"
#include<android/log.h>
#define LOG_TAG "System.out.c"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod1
(JNIEnv * env, jobject obj){
	//在C說話中調(diào)用Java的空辦法
	//1.找到j(luò)ava代碼native辦法地點的字節(jié)碼文件
	//jclass (*FindClass)(JNIEnv*, const char*);
	jclass clazz = (*env)->FindClass(env, "com/example/ndkcallback/DataProvider");
	if(clazz == 0){
		LOGD("find class error");
		return;
	}
	LOGD("find class");
	//2.找到class瑯綾擎對應(yīng)的辦法
	// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
	jmethodID method1 = (*env)->GetMethodID(env,clazz,"nullMethod","()V");
	if(method1 == 0){
		LOGD("find method1 error");
		return;
	}
	LOGD("find method1");
	//3.調(diào)用辦法
	//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
	(*env)->CallVoidMethod(env, obj, method1);
	LOGD("method1 called");
}

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod2
	(JNIEnv * env, jobject obj) {
	//1.找到j(luò)ava代碼native辦法地點的字節(jié)碼文件
	//jclass (*FindClass)(JNIEnv*, const char*);
	jclass clazz = (*env)->FindClass(env, "com/example/ndkcallback/DataProvider");
	if(clazz == 0){
		LOGD("find class error");
		return;
	}
	LOGD("find class");
	//2.找到class瑯綾擎對應(yīng)的辦法
	// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
	jmethodID method2 = (*env)->GetMethodID(env,clazz,"Add","(II)I");
	if(method2 == 0){
		LOGD("find method2 error");
		return;
	}
	LOGD("find method2");
	//3.調(diào)用辦法
	//jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
	int result = (*env)->CallIntMethod(env, obj, method2, 3,5);
	LOGD("result in C = %d", result);
}

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod3
(JNIEnv * env, jobject obj) {
	//1.找到j(luò)ava代碼native辦法地點的字節(jié)碼文件
	//jclass (*FindClass)(JNIEnv*, const char*);
	jclass clazz = (*env)->FindClass(env, "com/example/ndkcallback/DataProvider");
	if(clazz == 0){
		LOGD("find class error");
		return;
	}
	LOGD("find class");
	//2.找到class瑯綾擎對應(yīng)的辦法
	// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
	jmethodID method3 = (*env)->GetMethodID(env,clazz,"printString","(Ljava/lang/String;)V");
	if(method3 == 0){
		LOGD("find method3 error");
		return;
	}
	LOGD("find method3");
	//3.調(diào)用辦法
	//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
	(*env)->CallVoidMethod(env, obj, method3,(*env)->NewStringUTF(env,"haha in C ."));
	LOGD("method3 called");
}
留意:編寫C代碼時大年夜致須要如下3個重要的步調(diào):
jclass (*FindClass)(JNIEnv*, const char*);

1.找到j(luò)ava代碼native辦法地點的字節(jié)碼文件,在jni.h中的JNINativeInterface中可以找到

     個中第1個參數(shù)是JNINativeInterface的指針env,第2個參數(shù)是java辦法地點的類全路徑名,路徑之間用“/”來區(qū)分,弗成以應(yīng)用“.”
2.找到class瑯綾擎對應(yīng)的辦法,在jni.h中的JNINativeInterface中可以找到
獲取風(fēng)靜態(tài)辦法id:
jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);

獲取靜態(tài)辦法id:
jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);


      個中第1個參數(shù)是JNINativeInterface的指針env,第2個參數(shù)是java字節(jié)碼文件,第3個參數(shù)是java中的辦法名,第四個參數(shù)是java中對應(yīng)辦法的簽名。
3.調(diào)用辦法

void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
jobject     (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
jboolean    (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);
jbyte       (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...);
jchar       (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...);
jshort      (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...);
jlong       (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...);
jfloat      (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__;
jdouble     (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__;
       個中第1個參數(shù)是JNINativeInterface的指針env,第2個參數(shù)是java對象obj,第3個參數(shù)是找到的對應(yīng)java中的辦法,第4個參數(shù)是辦法接收的參數(shù)。這里列出的是常用的辦法,jni.h里的JNINativeInterface供給了大年夜量的辦法情勢用往返調(diào)java中的辦法,想懂得的請參考jni.h這個文件。

應(yīng)用javap敕令查看辦法簽名


       JDK為我們供給了如許的一個對象,該對象可以大年夜java字節(jié)碼文件中查看辦法的本地簽名,這個對象就是javap,應(yīng)用前,先在CMD的dos敕令行中,把路徑切換到工程中的java字節(jié)碼文件地點的目次下。
       敕令格式:javap -s 包名.辦法地點的Java類名
[img]http://img.blog.csdn.net/20141211151225651
如圖所示的那樣,黃色標注的是辦法名,是(*GetMethodID)(JNIEnv*, jclass, const char*, const char*)中的第3個參數(shù),紅色標注的是辦法簽名,是其第4個參數(shù)。

Android.mk設(shè)備和Application.mk設(shè)備


    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_MODULE    := Hello

    LOCAL_SRC_FILES := Hello.c
    
    LOCAL_LDLIBS += -llog

    include $(BUILD_SHARED_LIBRARY)
APP_PLATFORM := android-8

編譯C代碼


起首在cygwin中切換到當前工程目次下,履行“ndk-build clean”和“ndk-build”敕令
[img]http://img.blog.csdn.net/20141211152804367

在Java中調(diào)用Nattive辦法

public class MainActivity extends Activity implements OnClickListener {

	static {
		// 加載動態(tài)庫.so
		System.loadLibrary("Hello");
	}
	private Button btn1, btn2, btn3;
	private DataProvider provider;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		btn1 = (Button) findViewById(R.id.btn1);
		btn2 = (Button) findViewById(R.id.btn2);
		btn3 = (Button) findViewById(R.id.btn3);
		btn1.setOnClickListener(this);
		btn2.setOnClickListener(this);
		btn3.setOnClickListener(this);
		provider = new DataProvider();
	}
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
			case R.id.btn1 : // c回調(diào)java中的空辦法
				provider.callMethod1();
				break;
			case R.id.btn2 :// c回調(diào)java帶2個int參數(shù)的辦法
				provider.callMethod2();
				break;
			case R.id.btn3 :// c回調(diào)java帶string參數(shù)的辦法
				provider.callMethod3();
				break;
			default :
				break;
		}
	}

}

測試


[img]http://img.blog.csdn.net/20141211153429001
留意:以下測試的LOG中,綠色代表Java生成的LOG,藍色代表C生成的LOG。
測試1:c回調(diào)java中的空辦法
[img]http://img.blog.csdn.net/20141211153444265
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_ndkcallback_DataProvider */

#ifndef _Included_com_example_ndkcallback_DataProvider
#define _Included_com_example_ndkcallback_DataProvider
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_ndkcallback_DataProvider
 * Method:    callMethod1
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod1
(JNIEnv *, jobject);

/*
 * Class:     com_example_ndkcallback_DataProvider
 * Method:    callMethod2
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod2
(JNIEnv *, jobject);

/*
 * Class:     com_example_ndkcallback_DataProvider
 * Method:    callMethod3
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod3
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

編寫C代碼


測試2:c回調(diào)java帶2個int參數(shù)的辦法
[img]http://img.blog.csdn.net/20141211153448189
測試3:c回調(diào)java帶string參數(shù)的辦法
[img]http://img.blog.csdn.net/20141211153500843
JNIEXPORT void JNICALL Java_com_example_ndkcallback_MainActivity_callMethod4
  (JNIEnv * env, jobject obj){
	//1.找到j(luò)ava代碼native辦法地點的字節(jié)碼文件
		//jclass (*FindClass)(JNIEnv*, const char*);
		jclass clazz = (*env)->FindClass(env, "com/example/ndkcallback/DataProvider");
		if(clazz == 0){
			LOGD("find class error");
			return;
		}
		LOGD("find class");
		//2.找到class瑯綾擎對應(yīng)的辦法
		// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
		jmethodID method4 = (*env)->GetMethodID(env,clazz,"nullMethod","()V");
		if(method4 == 0){
			LOGD("find method4 error");
			return;
		}
		LOGD("find method4");
		//3.經(jīng)由過程jclass獲取jobject
		//jobject     (*AllocObject)(JNIEnv*, jclass);
		jobject jobj = (*env)->AllocObject(env, clazz);
		if(jobj == 0){
			LOGD("find jobj error");
			return;
		}
		LOGD("find jobj");
		//4.調(diào)用辦法
		//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
		(*env)->CallVoidMethod(env, jobj, method4);
		LOGD("method4 called");
}
      寫完代碼之后,從新編譯C代碼文件,Refresh和clean一下工程,運行后:

別的:native代碼與調(diào)用的java代碼不在同一個類里


       上述建立的Android工程中,native代碼和調(diào)用的java代碼是放在同一個DataProvider類中的,如許在C代碼中調(diào)用Java代碼是異常便利的。然則,平日開辟中我們不必定就這么干,一個項目中java文件很多,如果在其它的java文件中定義了native辦法了,然后再去調(diào)另一個java類里的Java辦法,這種情況下會出現(xiàn)什憒問題呢?帶著這個疑問,我們就在MainActivity.java文件中定義一個native辦法,這個native辦法又要調(diào)用DataProvider類的nullMethod辦法。
在MainActivity.java中,我們定義如許的辦法:
private native void callMethod4();
切換到這個src目次下javah獲取函數(shù)簽名,將獲得的簽名頭文件拷貝到j(luò)ni目次下,在C文件中引用這個頭文件,編寫響應(yīng)的C代碼:
JNIEXPORT void JNICALL Java_com_example_ndkcallback_MainActivity_callMethod4
  (JNIEnv * env, jobject obj){
	//1.找到j(luò)ava代碼native辦法地點的字節(jié)碼文件
		//jclass (*FindClass)(JNIEnv*, const char*);
		jclass clazz = (*env)->FindClass(env, "com/example/ndkcallback/DataProvider");
		if(clazz == 0){
			LOGD("find class error");
			return;
		}
		LOGD("find class");
		//2.找到class瑯綾擎對應(yīng)的辦法
		// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
		jmethodID method4 = (*env)->GetMethodID(env,clazz,"nullMethod","()V");
		if(method4 == 0){
			LOGD("find method4 error");
			return;
		}
		LOGD("find method4");
		//3.調(diào)用辦法
		//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
		(*env)->CallVoidMethod(env, obj, method4);
		LOGD("method4 called");
}
編譯運行之后,報錯了
[img]http://img.blog.csdn.net/20141211171250055
       實際運行的時刻,法度榜樣直接崩潰了,查看日記發(fā)明,字節(jié)碼class找到了,辦法method找到了,然則就是沒有履行method辦法,顯然是履行method辦法這行代碼出了Bug,以下是調(diào)用method辦法履行的代碼:
(*env)->CallVoidMethod(env, obj, method4);
       那么這行代碼是為什么報錯了呢?細心不雅察一下,CallVoidMethod辦法的第2個參數(shù)obj,這個obj是jobject類型的,默認是java native辦法地點的類的對象,就是MainActivity類的對象,然則這個native辦法實際上調(diào)用的java辦法存在于DataProvider類的nullMethod,調(diào)用nullMethod顯然須要應(yīng)用DataProvider類的對象。反正就一句話:obj對象不精確,須要java辦法對應(yīng)的對象,即DataProvider。

創(chuàng)建工程,在工程瑯綾擎定義Java辦法和Native辦法


       知道問題了,就可以著手解決問題了。在jni.h的頭文件中,JNINativeInterface供給了如許的一個辦法,贊助我們經(jīng)由過程字節(jié)碼jclass找到對應(yīng)的對象:
jobject     (*AllocObject)(JNIEnv*, jclass);
       這個辦法第1個參數(shù)是JNINativeInterface,第2個參數(shù)是jclass,返回值jobject。我們就拿這個辦法獲取jobject,傳給CallVoidMethod:

[img]http://img.blog.csdn.net/20141211173234721
源碼請在這里下載

相關(guān)案例查看更多