【學習Android NDK開發】native code通過JNI調用Java方法


1、建立Android應用

application name: CallJavaMethod

package name: com.example.cjm

main Activity: MainActivity

main Activity layout: activity_main

 

2、Java實現

打開layout/activity_main.xml布局文件,添加按鈕控件,ID為“display_button_activity_main”

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button
        android:id="@+id/display_button_activity_main"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Display"
        tools:context=".MainActivity" />

</RelativeLayout>

 

新建接口CJMListener,定義接口方法displaymessage

package com.example.cjm;

public interface CJMListener {
    void displayMessage(String message);
}

 

新建類CJM,實現接口CJMListener

定義native public方法displaySomething

package com.example.cjm;

import android.os.Handler;

public class CJM implements CJMListener {
    
    static {
        System.loadLibrary("cjm");
    }
    
    private Handler handler;
    private CJMListener listener;
    
    public CJM(CJMListener listener) {
        handler = new Handler();
        this.listener = listener;
    }

    @Override
    public void displayMessage(final String message) {
        handler.post(new Runnable() {

            @Override
            public void run() {
                listener.displayMessage(message);
            }
        });
    }
    
    public native void displaySomething();

}

 

為MainActivity類,實現CJMListener,添加CMJ對象域

添加Button對象域,引用在布局文件中定義ID為“display_button_activity_main”的按鈕控件

package com.example.cjm;

import android.os.Handler;

public class CJM implements CJMListener {
    
    static {
        System.loadLibrary("cjm");
    }
    
    private Handler handler;
    private CJMListener listener;
    
    public CJM(CJMListener listener) {
        handler = new Handler();
        this.listener = listener;
    }

    @Override
    public void displayMessage(final String message) {
        handler.post(new Runnable() {

            @Override
            public void run() {
                listener.displayMessage(message);
            }
        });
    }
    
    public native void displaySomething();

}

 

當用戶按下按鈕,執行CJM對象的displaySomething方法

類CJM的displaySomething方法使用native關鍵字進行聲明,將使用native code實現

實現上,在nativie code中,會回調CJM對象的displayerMessage方法,並傳遞String類型的消息,用於顯示

注意,在CJM類中displayerMessage的實現,由於native code並不是在主線程中執行,所以使用了Android的Handler執行MainActivity的方法

 

3、C實現

使用javah為CJM的native方法生成頭文件(步驟省略……)

新建.c文件,實現該頭文件的方法

#include "com_example_cjm_CJM.h"

JNIEXPORT void JNICALL Java_com_example_cjm_CJM_displaySomething
  (JNIEnv *env, jobject thiz) {

    jclass ClassCJM = (*env)->FindClass(env, "com/example/cjm/CJM");
    jmethodID MethodDisplayMessage = (*env)->GetMethodID(env, ClassCJM, "displayMessage", "(Ljava/lang/String;)V");
    jstring value = (*env)->NewStringUTF(env, "Hello World!");
    (*env)->CallVoidMethod(env, thiz, MethodDisplayMessage, value);

}

 

JNI調用Java方法的步驟:

1) 獲取jmethodID;

GetMethodID

jmethodID GetMethodID(JNIEnv *env, jclass clazz,
const char *name, const char *sig);

Returns the method ID for an instance (nonstatic) method of a class or interface. The method may be defined in one of the clazz’s superclasses and inherited by clazz. The method is determined by its name and signature.

GetMethodID() causes an uninitialized class to be initialized.

To obtain the method ID of a constructor, supply <init> as the method name and void (V) as the return type.

2) 調用Java方法;

NativeType Call<type>Method(JNIEnv *env, jobject obj,
jmethodID methodID, ...);

Methods from these three families of operations are used to call a Java instance method from a native method.They only differ in their mechanism for passing parameters to the methods that they call.

These families of operations invoke an instance (nonstatic) method on a Java object, according to the specified method ID. The methodID argument must be obtained by calling GetMethodID().

When these functions are used to call private methods and constructors, the method ID must be derived from the real class of obj, not from one of its superclasses.

Instance Method Calling Routines:

CallVoidMethod void
CallObjectMethod jobject
CallBooleanMethod jboolean
CallByteMethod jbyte
CallCharMethod jchar
CallShortMethod jshort
CallIntMethod jint
CallLongMethod jlong
CallFloatMethod jfloat
CallDoubleMethod jdouble

 

 

運行結果截圖:

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM