[Android初級]NDK入門體驗の方法調用

來源:互聯網
上載者:User

標籤:android   ndk   jni   

    本文屬於自我複習,內容重複請勿見怪

如何在android應用的自訂底層C中調用java的代碼?這是本次自我複習的計劃。

首先,我得建立一個demo,結構如下:


1.建立一個介面類NativeDataProvider,他的作用是調用c方法,然後回調java方法

public class NativeDataProvider {static final String TAG = "NativeDataProvider";private Context context;public NativeDataProvider(Context context){this.context = context;}//調用C中的代碼public native void callCCode();public native int callCAdd(int i,int j);public native void callCPrintString();//在C中調用java中的org.jan.ndk.example.NativeDataProvider無參方法helloFrmJavapublic void helloFromJava(){Log.i(TAG, "hello from java!");Toast.makeText(context, "hello from java", Toast.LENGTH_SHORT).show();}//在C中調用參數為string的方法public void printString(String str){Log.i(TAG, "[from java]:"+str);Toast.makeText(context, "printString->str:"+str, Toast.LENGTH_SHORT).show();}//在c中調用int參數的方法public int add(int i,int j){int result = i+j;Log.i(TAG, "result is"+result);Toast.makeText(context, "add->result="+result, Toast.LENGTH_SHORT).show();return result;}}

2.建立Android.mk

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := jni_demoLOCAL_SRC_FILES := jni_demo.c#增加log庫LOCAL_LDLIBS += -llog include $(BUILD_SHARED_LIBRARY)
3.建立jni,也就是c代碼,之前先建立NativeDataProvider的標頭檔,到項目目錄/bin/classes下,調用 javah org.jan.ndk.example.NativeDataProvider

就會產生org_jan_ndk_example_NativeDataProvider.h

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class org_jan_ndk_example_NativeDataProvider */#ifndef _Included_org_jan_ndk_example_NativeDataProvider#define _Included_org_jan_ndk_example_NativeDataProvider#ifdef __cplusplusextern "C" {#endif/* * Class:     org_jan_ndk_example_NativeDataProvider * Method:    callCCode * Signature: ()V */JNIEXPORT void JNICALL Java_org_jan_ndk_example_NativeDataProvider_callCCode  (JNIEnv *, jobject);/* * Class:     org_jan_ndk_example_NativeDataProvider * Method:    callCAdd * Signature: (II)I */JNIEXPORT jint JNICALL Java_org_jan_ndk_example_NativeDataProvider_callCAdd  (JNIEnv *, jobject, jint, jint);/* * Class:     org_jan_ndk_example_NativeDataProvider * Method:    callCPrintString * Signature: ()V */JNIEXPORT void JNICALL Java_org_jan_ndk_example_NativeDataProvider_callCPrintString  (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif

其中看到有Signature:()V 這樣類似的 就是 方法簽名。

例如:

har* classname = "org/jan/ndk/example/NativeDataProvider";
jclass dpclazz = (*env)->FindClass(env, classname);

這是通過jnienv指標擷取class對象。


jmethodID methodID = (*env)->GetMethodID(env, dpclazz, "helloFromJava", "()V");

GetMethodID指 從java中擷取定義好的method方法,第二個參數是class對象,第三個參數是方法名,第四個是方法簽名(可以從標頭檔中看Signature)

看方法簽名的方法: 進入項目\bin\classes 下,命令:javap -s org.jan.ndk.example.NativeDataProvider

"()V"的大概意思就是 括弧內沒有參數,就是沒有入參,V就是void無返回值。



下面是C主要代碼(具體請看注釋):

#include "org_jan_ndk_example_NativeDataProvider.h"#include <string.h>#include <android/log.h>#define LOG_TAG "System.out"#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_org_jan_ndk_example_NativeDataProvider_callCCode  (JNIEnv * env, jobject obj){//調用NativeDataProvider對象中的helloFromJava()方法//擷取到某個對象, 擷取對象中的方法, 調用擷取到的方法LOGI("in code");//NativeDataProvider完整類名 org.jan.ndk.example.NativeDataProviderchar* classname = "org/jan/ndk/example/NativeDataProvider";jclass dpclazz = (*env)->FindClass(env, classname);if(dpclazz == 0)LOGI("org.jan.ndk.example.NativeDataProvider.class not find !!!");elseLOGI("org.jan.ndk.example.NativeDataProvider.class find !!!");//使用jni.h中提供的GetMethodID方法, 擷取jmethodID, 傳入參數 ①JNIEnv指標 ②Class對象 ③ 方法名 ④方法簽名, 在這裡方法名和方法簽名確定一個方法, 方法簽名就是方法的傳回值 與 參數的唯一標示;//參數介紹 : 第二個參數是Class對象, 第三個參數是方法名,第四個參數是方法的簽名, 擷取到調用的methodjmethodID methodID = (*env)->GetMethodID(env, dpclazz, "helloFromJava", "()V");if(methodID == 0)LOGI("method helloFromJava not find !!!");elseLOGI("method helloFromJava find !!!");/* * 調用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); * 參數介紹 : 後面的 ... 是可變參數, 如果該傳回值void的方法有參數, 就將參數按照次序排列 */LOGI("before call method");(*env)->CallVoidMethod(env, obj, methodID);LOGI("after call method");}JNIEXPORT void JNICALL Java_org_jan_ndk_example_NativeDataProvider_callCPrintString  (JNIEnv *env, jobject obj){//調用DataProvider對象中的helloFromJava()方法//擷取到某個對象, 擷取對象中的方法, 調用擷取到的方法LOGI("in code");//NativeDataProvider完整類名 org.jan.ndk.example.NativeDataProviderchar* classname = "org/jan/ndk/example/NativeDataProvider";jclass dpclazz = (*env)->FindClass(env, classname);if(dpclazz == 0)LOGI("class not find !!!");elseLOGI("class find !!!");//參數介紹 : 第二個參數是Class對象, 第三個參數是方法名,第四個參數是方法的簽名, 擷取到調用的methodjmethodID methodID = (*env)->GetMethodID(env, dpclazz, "printString", "(Ljava/lang/String;)V");if(methodID == 0)LOGI("method not find !!!");elseLOGI("method find !!!");/* * 調用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); * 參數介紹 : 後面的 ... 是可變參數, 如果該傳回值void的方法有參數, 就將參數按照次序排列 */LOGI("before call method");(*env)->CallVoidMethod(env, obj, methodID, (*env)->NewStringUTF(env, "printString method callback success!!"));LOGI("after call method");}/* * 實際開發的情況 * C代碼工程師給我們 first.h first.c , 我們只需要將first.h引入, 然後就可以使用其中的方法了 */JNIEXPORT jint JNICALL Java_org_jan_ndk_example_NativeDataProvider_callCAdd(JNIEnv *env, jobject obj, jint a, jint b){//調用DataProvider對象中的helloFromJava()方法//擷取到某個對象, 擷取對象中的方法, 調用擷取到的方法LOGI("in code test_add=>");//NativeDataProvider完整類名 org.jan.ndk.example.NativeDataProviderchar* classname = "org/jan/ndk/example/NativeDataProvider";jclass dpclazz = (*env)->FindClass(env, classname);if(dpclazz == 0)LOGI("class not find !!!");elseLOGI("class find !!!");//參數介紹 : 第二個參數是Class對象, 第三個參數是方法名,第四個參數是方法的簽名, 擷取到調用的methodjmethodID methodID = (*env)->GetMethodID(env, dpclazz, "add", "(II)I");if(methodID == 0)LOGI("method not find !!!");elseLOGI("method find !!!");/* * 調用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); * 參數介紹 : 後面的 ... 是可變參數, 如果該傳回值void的方法有參數, 就將參數按照次序排列 */return (*env)->CallIntMethod(env, obj, methodID, a,b);}

4.編譯jni,在demo目錄下手動執行ndk-build

5.android的代碼:

public class MainActivity extends ActionBarActivity {private static final String TAG = "MainActivity";private static NativeDataProvider ndp;static{System.loadLibrary("jni_demo");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ndp = new NativeDataProvider(this);if (savedInstanceState == null) {getSupportFragmentManager().beginTransaction().add(R.id.container, new PlaceholderFragment()).commit();}}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.int id = item.getItemId();if (id == R.id.action_settings) {return true;}return super.onOptionsItemSelected(item);}/** * A placeholder fragment containing a simple view. */public static class PlaceholderFragment extends Fragment implements OnClickListener {private Button callVoidMethod, callStringMethod, callIntMethod;public PlaceholderFragment() {}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View rootView = inflater.inflate(R.layout.fragment_main, container,false);callVoidMethod = (Button) rootView.findViewById(R.id.call_void_method_btn);callStringMethod = (Button) rootView.findViewById(R.id.call_string_parameter_method);callIntMethod = (Button) rootView.findViewById(R.id.call_int_parameter_method);callVoidMethod.setOnClickListener(this);callStringMethod.setOnClickListener(this);callIntMethod.setOnClickListener(this);return rootView;}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.call_void_method_btn:ndp.callCCode();break;case R.id.call_string_parameter_method:ndp.callCPrintString();break;case R.id.call_int_parameter_method:ndp.callCAdd(2,3);break;}}}}

實現結果如下:



程式碼範例下載:請開啟如意門下載




[Android初級]NDK入門體驗の方法調用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.