1. 程式人生 > >Android開發 通過JNI實現JAVA與C/C++程式間的呼叫和回撥

Android開發 通過JNI實現JAVA與C/C++程式間的呼叫和回撥

       在一些Android應用的開發中,需要通過JNI Android NDK工具實現JAVAC/C++之間的相互呼叫。

       Java Native Interface (JNI)標準是java平臺的一部分,它允許Java程式碼和其他語言寫的程式碼進行互動。JNI是本地程式設計介面,它使得在 Java 虛擬機器 (VM)內部執行的 Java程式碼能夠與用其它程式語言( CC++和組合語言)編寫的應用程式和庫進行互動操作。

       由於Android的應用層的類都是以Java寫的,這些Java類編譯為Dex型式的Bytecode之後,必須靠Dalvik虛擬機器(VM: Virtual Machine)

來執行。在執行Java類的過程中,如果Java類需要與C元件溝通時,VM就會去載入C元件,然後讓Java的函式順利地呼叫到C元件的函式。此時,VM扮演著橋樑的角色,讓JavaC元件能通過標準的JNI介面而相互溝通。

       在實際應用中這兩者之間的呼叫關係可以歸納為以下四種方式:

             1.       在應用的JAVA程式碼中呼叫NDKC/C++實現的函式。

             2.       在NDK開發中的C/C++程式碼呼叫應用中JAVA類的靜態函式。

             3.       在NDK開發中的C/C++程式碼呼叫應用中JAVA類當前傳入NDK

中的例項的函式。

            4.       在NDK開發中的C/C++程式碼呼叫應用中JAVA類新建例項的函式。

下面我們就怎樣在Eclipse中實現JNI編碼和四種呼叫方式加以闡述。

一、Eclipse中建立一個包含JNI開發的工程。

在這裡我們不直接匯入NDK中的hello-jni來說明JNI的使用方法。而是新建立一個工程,來說明怎樣建立一個包含JNI的工程。

第一步:建立一個Andriod工程JniDemo,在該工程的根目錄下建立一個叫jni的目錄,在jni目錄下建立一個叫Android.mk的檔案,(當然你也可以從其他地方,比如ndk樣例程式碼hello-jni中將裡面的Android.mk

複製過來修改) Android.mk裡面的內容如下所示

LOCAL_PATH :=$(call my-dir)

include$(CLEAR_VARS)

LOCAL_MODULE   := demo-jni

LOCAL_SRC_FILES := demo-jni.c

include$(BUILD_SHARED_LIBRARY)

關於這幾句話的含義,在這裡不再贅述。網上搜下,就可以很明白。

然後在jni目錄下生成demo-jni.c檔案。實現的介面的內容。

現在選中工程中的jni目錄,點選滑鼠右鍵,選Refreshjni目錄中的檔案就顯示在工程的jni目錄下了。

第二步:設定jni的編譯環境。選中工程中的根目錄JniDemo,點選滑鼠右鍵,選Properties。彈出對話方塊,選中列表中的Builders。如圖一所示:

圖一:JniDemo特性設定對話方塊

點選對話方塊右端的new按鈕,彈出“Choose configuration type”對話方塊,如圖二,選擇Program,點選對話方塊下面的OK按鈕。

圖二:選擇配置型別

現在我們打開了”Edit Configuration”對話方塊,在Name對應的文字框中輸入名字JniBuilder(當然也可是你喜歡的其他名字).Main選項下,Location中輸入cygwin系統中bash.exe的絕對路徑。我這裡是c:\cygwin\bin\bash.exec:\cygwin\為我的系統中cygwin的安裝目錄,這裡要根據你的電腦中cygwin的安裝目錄來確定),Working Directory中輸入c:\cygwin\bin\.Arguments中輸入--login -c "cd /cygdrive/d/study/JniDemo && /cygdrive/d/android-ndk-r6b/ndk-build"。這裡/cygdrive/d/study/JniDemo為工程根目錄, /cygdrive/d/android-ndk-r6bNDK的安裝目錄。這兩個目錄引數根據你的工程目錄和ndk的安裝目錄而定。注意的是驅動器要採用cygwin的方式。(比如:Windows系統下的D:對應/cygdrive/d,其餘類推)。設定結果如圖三所示,然後點選 OK按鈕即可。

圖三:編輯JNI配置引數

二、演示四種呼叫方式

演示介面如圖四所示,四個按鈕分別測試四種呼叫方式。

圖四:演示介面圖

分別點選按鈕Test1, Test2, Tes3, Test四的測試結果如圖五、六、七、八所示。

圖五:點選Test1的測試結果

圖六:點選Test2的測試結果

圖七:點選Test3的測試結果

圖八:點選Test4的測試結果

Test1演示在應用中呼叫NDKC/C++實現的函式。JAVA程式碼和C程式碼分別為:

JAVA 程式碼:

[java] view plaincopyprint?
  1. Button btn01 = (Button)findViewById(R.id.Button01);  
  2. btn01.setOnClickListener(new Button.OnClickListener()  
  3. {  
  4.     publicvoid onClick(View v)  
  5.     {        
  6.         TextView tv = (TextView)findViewById(R.id.tv01);  
  7.         tv.setText(stringFromJNI());              
  8.         showMessage(JniDemoActivity.this,"JNI test1", stringFromJNI());  
  9.     }  
  10. });  
    Button btn01 = (Button)findViewById(R.id.Button01);
    btn01.setOnClickListener(new Button.OnClickListener()
    {
        publicvoid onClick(View v)
        {      
            TextView tv = (TextView)findViewById(R.id.tv01);
            tv.setText(stringFromJNI());            

            showMessage(JniDemoActivity.this,"JNI test1", stringFromJNI());
        }
    });

C程式碼:

[cpp] view plaincopyprint?
  1. Jstring Java_study_jnidemo_JniDemoActivity_stringFromJNI( JNIEnv* env,jobject thiz )  
  2. {  
  3.     return (*env)->NewStringUTF(env,"JniDemo, Hello from JNI!");  
  4. }  
Jstring Java_study_jnidemo_JniDemoActivity_stringFromJNI( JNIEnv* env,jobject thiz )

{
    return (*env)->NewStringUTF(env,"JniDemo, Hello from JNI!");
}


l         Test2 靜態呼叫。JAVA程式碼和C程式碼分別為:

JAVA 程式碼:

[java] view plaincopyprint?
  1. // 測試C/C++中對JAVA函式的靜態回撥
  2. Button btn02 = (Button)findViewById(R.id.Button02);  
  3. btn02.setOnClickListener(new Button.OnClickListener()  
  4. {  
  5.     publicvoid onClick(View v)  
  6.     {  
  7.         int ret =jniStaticShowMessage(JniDemoActivity.this,"JNI test2","test static callback Message");  
  8.         TextView tv = (TextView)findViewById(R.id.tv01);  
  9.         if(ret == 0)  
  10.         {  
  11.            tv.setText("test JNI static callback successed");  
  12.         }  
  13.         else
  14.         {  
  15.            tv.setText("test JNI static callback fialed");  
  16.         }  
  17.     }  
  18. });  
    // 測試C/C++中對JAVA函式的靜態回撥
    Button btn02 = (Button)findViewById(R.id.Button02);
    btn02.setOnClickListener(new Button.OnClickListener()
    {
        publicvoid onClick(View v)
        {
            int ret =jniStaticShowMessage(JniDemoActivity.this,"JNI test2","test static callback Message");
            TextView tv = (TextView)findViewById(R.id.tv01);
            if(ret == 0)
            {
               tv.setText("test JNI static callback successed");
            }
            else
            {
               tv.setText("test JNI static callback fialed");
            }
        }
    });


C程式碼:

[cpp] view plaincopyprint?
  1. Jint Java_study_jnidemo_JniDemoActivity_jniStaticShowMessage(JNIEnv* env,   
Jint Java_study_jnidemo_JniDemoActivity_jniStaticShowMessage(JNIEnv* env, 
[cpp] view plaincopyprint?
  1.                         jobject thiz,jobject ctx, jstring strTitle, jstring strMessage)  
  2. {  
  3.     jclass cls = (*env)->FindClass(env, "study/jnidemo/JniDemoActivity");  
  4. //  jclass cls = (*env)->GetObjectClass(env, thiz);
  5.     if(cls != NULL)  
  6.     {  
  7.        jmethodID id = (*env)->GetStaticMethodID(env, cls,"staticShowMessage",  
  8.             "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");  
  9.        if(id != NULL)  
  10.        {  
  11.       return (*env)->CallStaticIntMethod(env, cls, id, ctx, strTitle, strMessage);  
  12.        }  
  13.     }  
  14.     return 1;  
  15. }  
						jobject thiz,jobject ctx, jstring strTitle, jstring strMessage)
{
    jclass cls = (*env)->FindClass(env, "study/jnidemo/JniDemoActivity");
//  jclass cls = (*env)->GetObjectClass(env, thiz);
    if(cls != NULL)
    {
       jmethodID id = (*env)->GetStaticMethodID(env, cls,"staticShowMessage",
			"(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");
       if(id != NULL)
       {
	  return (*env)->CallStaticIntMethod(env, cls, id, ctx, strTitle, strMessage);
       }
    }
    return 1;
}


l         Test3 當前例項呼叫:JAVA程式碼和C程式碼分別為:

JAVA 程式碼:

[java] view plaincopyprint?
  1. Button btn03 = (Button)findViewById(R.id.Button03);  
  2. btn03.setOnClickListener(new Button.OnClickListener()  
  3. {  
  4.     publicvoid onClick(View v)  
  5.     {  
  6.         strTest = " [message has changed now]";  
  7.         int ret = jniShowMessage(JniDemoActivity.this,"JNI test3","test callback in current instance");  
  8.         TextView tv = (TextView)findViewById(R.id.tv01);              
  9.         if(ret == 0)  
  10.         {  
  11.            tv.setText("test JNI callback successed");                        
  12.         }  
  13.         else
  14.         {  
  15.            tv.setText("test JNI callback fialed");  
  16.         }  
  17.     }  
  18. });  
    Button btn03 = (Button)findViewById(R.id.Button03);
    btn03.setOnClickListener(new Button.OnClickListener()
    {
        publicvoid onClick(View v)
        {
            strTest = " [message has changed now]";
            int ret = jniShowMessage(JniDemoActivity.this,"JNI test3","test callback in current instance");
            TextView tv = (TextView)findViewById(R.id.tv01);            

            if(ret == 0)
            {
               tv.setText("test JNI callback successed");                      
            }
            else
            {
               tv.setText("test JNI callback fialed");
            }
        }
    });

C程式碼:

[cpp] view plaincopyprint?
  1. Jint Java_study_jnidemo_JniDemoActivity_jniShowMessage(JNIEnv* env, jobject thiz,  
  2.        jobject ctx, jstring strTitle, jstring strMessage)  
  3. {  
  4.     jclass cls = (*env)->GetObjectClass(env, thiz);  
  5.     if(cls != NULL)  
  6.     {  
  7.        jstring str;  
  8.        jmethodID strTest_id = (*env)->GetMethodID(env, cls, "getTestString","()Ljava/lang/String;");  
  9.        if(strTest_id != NULL)  
  10.        {  
  11.           str = (*env)->CallObjectMethod(env, thiz, strTest_id);  
  12.        }   
  13.        jmethodID showMessage_id = (*env)->GetMethodID(env, cls, "showMessage",  
  14.     "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");   
  15.        if(showMessage_id != NULL)  
  16.        {  
  17.           return (*env)->CallIntMethod(env, thiz, showMessage_id, ctx,  
  18.                  strTitle, combine_jstring(env, strMessage, str));  
  19.        }  
  20.     }  
  21.     return 1;  
  22. }  
Jint Java_study_jnidemo_JniDemoActivity_jniShowMessage(JNIEnv* env, jobject thiz,
       jobject ctx, jstring strTitle, jstring strMessage)

{
    jclass cls = (*env)->GetObjectClass(env, thiz);
    if(cls != NULL)
    {
       jstring str;
       jmethodID strTest_id = (*env)->GetMethodID(env, cls, "getTestString","()Ljava/lang/String;");

       if(strTest_id != NULL)

       {
          str = (*env)->CallObjectMethod(env, thiz, strTest_id);
       } 

       jmethodID showMessage_id = (*env)->GetMethodID(env, cls, "showMessage",
	"(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I"); 

       if(showMessage_id != NULL)
       {
          return (*env)->CallIntMethod(env, thiz, showMessage_id, ctx,
                 strTitle, combine_jstring(env, strMessage, str));
       }
    }
    return 1;
}


l         Test4新建例項呼叫:JAVA程式碼和C程式碼分別為:

JAVA 程式碼:

[java] view plaincopyprint?
  1. Button btn04 = (Button)findViewById(R.id.Button04);  
  2. btn04.setOnClickListener(newButton.OnClickListener()  
  3. {  
  4.     publicvoid onClick(View v)  
  5.     {  
  6.         strTest = " [message has changed now]";  
  7.         int ret = jniInstanceShowMessage(JniDemoActivity.this,  
  8. JNI test4","test callback in new instance");  
  9.         TextView tv = (TextView)findViewById(R.id.tv01);              
  10.         if(ret == 0)  
  11.         {  
  12.            tv.setText("test JNI new instance successed");        
  13.         }  
  14.        else
  15.         {  
  16.            tv.setText("test JNI new instance fialed");  
  17.         }  
  18.     }  
  19. });  
    Button btn04 = (Button)findViewById(R.id.Button04);
    btn04.setOnClickListener(newButton.OnClickListener()
    {
        publicvoid onClick(View v)
        {
            strTest = " [message has changed now]";
            int ret = jniInstanceShowMessage(JniDemoActivity.this,
		 "JNI test4","test callback in new instance");
            TextView tv = (TextView)findViewById(R.id.tv01);            

            if(ret == 0)
            {
               tv.setText("test JNI new instance successed");      
            }
           else
            {
               tv.setText("test JNI new instance fialed");
            }
        }
    });


C程式碼:

[cpp] view plaincopyprint?
  1. jint Java_study_jnidemo_JniDemoActivity_jniInstanceShowMessage(JNIEnv* env, jobject thiz,  
  2.        jobject ctx, jstring strTitle, jstring strMessage)  
  3. {  
  4.     jclass cls = (*env)->FindClass(env, "study/jnidemo/JniDemoActivity");  
  5.     if(cls != NULL)  
  6.     {  
  7.        // get instance
  8.        jmethodID constuctor_id = (*env)->GetMethodID(env, cls, "<init>""()V");  
  9.        if(constuctor_id != NULL)  
  10.        {  
  11.           jobject obj = (*env)->NewObject(env, cls, constuctor_id);  
  12.           if(obj != NULL)  
  13.           {  
  14.              jstring str;  
  15.              jmethodID strTest_id = (*env)->GetMethodID(env, cls, "getTestString","()Ljava/lang/String;");  
  16.              if(strTest_id != NULL)  
  17.              {  
  18.                  str = (*env)->CallObjectMethod(env, obj, strTest_id);  
  19.              }  
  20.              jmethodID showMessage_id = (*env)->GetMethodID(env, cls,"showMessage",  
  21.                     "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");  
  22.              if(showMessage_id != NULL)  
  23.              {  
  24.                  return (*env)->CallIntMethod(env, obj, showMessage_id, ctx,strTitle, combine_jstring(env, strMessage, str));  
  25.              }  
  26.           }  
  27.        }  
  28.     }  
  29.     return 1;  
  30. }  
jint Java_study_jnidemo_JniDemoActivity_jniInstanceShowMessage(JNIEnv* env, jobject thiz,
       jobject ctx, jstring strTitle, jstring strMessage)
{
    jclass cls = (*env)->FindClass(env, "study/jnidemo/JniDemoActivity");
    if(cls != NULL)
    {
       // get instance
       jmethodID constuctor_id = (*env)->GetMethodID(env, cls, "<init>", "()V");
       if(constuctor_id != NULL)
       {
          jobject obj = (*env)->NewObject(env, cls, constuctor_id);
          if(obj != NULL)
          {
             jstring str;
             jmethodID strTest_id = (*env)->GetMethodID(env, cls, "getTestString","()Ljava/lang/String;");
             if(strTest_id != NULL)
             {
                 str = (*env)->CallObjectMethod(env, obj, strTest_id);
             }
             jmethodID showMessage_id = (*env)->GetMethodID(env, cls,"showMessage",
                    "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");
             if(showMessage_id != NULL)
             {
                 return (*env)->CallIntMethod(env, obj, showMessage_id, ctx,strTitle, combine_jstring(env, strMessage, str));
             }
          }
       }
    }
    return 1;
}


Test1 Test2都是常規的呼叫,在這裡不做解釋了。現在我們看看Test3Test4的區別,在Test3中,strTest = " [message has changed now]" 在相應的程式碼中都做了賦值。但是在Test4中並沒有改變,還是初始值。這是因為Test建立了一個新例項,和應用的JAVA程式碼中所賦值的例項並不是同一個。因此才出現了不同的結果。

附完整的JAVAC程式碼

JAVAD程式碼: JniDemoActivity.java

[java] view plaincopyprint?
  1. package study.jnidemo;   
  2. import android.app.Activity;  
  3. import android.app.AlertDialog;  
  4. import android.os.Bundle;  
  5. import android.widget.Button;  
  6. import android.view.View;  
  7. import android.widget.TextView;  
  8. import android.content.Context;  
  9. import android.content.DialogInterface;   
  10. publicclass JniDemoActivityextends Activity {      
  11.     public StringstrTest =" [initial message]";             
  12.     /** Called when the activity is first created. */
  13.     @Override
  14.     publicvoid onCreate(Bundle savedInstanceState) {  
  15.         super.onCreate(savedInstanceState);  
  16.         setContentView(R.layout.main);         
  17.         findAndModifyButton();  
  18.     }  
  19.     public String getTestString()  
  20.     {  
  21.         returnstrTest;  
  22.     }     
  23.     // 測試JAVA的NDK呼叫
  24.     publicnative String stringFromJNI();      
  25.     // 測試C/C++中對JAVA函式的靜態回撥
  26.     publicnativestaticint jniStaticShowMessage(Context ctx, String strTitle, String strMessage);      
  27.     // 測試例項中C/C++中對JAVA類的函式的呼叫
  28.     publicnativeint jniShowMessage(Context ctx, String strTitle, String strMessage);      
  29.     // 測試建立新例項C/C++對JAVA類的函式的呼叫
  30.     publicnativeint jniInstanceShowMessage(Context ctx, String strTitle, String strMessage);      
  31.     static {  
  32.         System.loadLibrary("demo-jni");  
  33.     }      
  34.     staticint staticShowMessage(Context ctx, String strTitle, String strMessage)  
  35.     {     
  36.         AlertDialog.Builder builder = new AlertDialog.Builder(ctx);     
  37.         builder.setTitle(strTitle);  
  38.         builder.setMessage(strMessage);  
  39.         builder.setPositiveButton("確定",  
  40.          new DialogInterface.OnClickListener(){  
  41.                publicvoid onClick(DialogInterface dialog,int whichButton){               
  42.                }  
  43.         });  
  44.         builder.show();      
  45.         return0;  
  46.     }     
  47.     publicint showMessage(Context ctx, String strTitle, String strMessage)  
  48.     {  
  49.         returnstaticShowMessage(ctx, strTitle, strMessage);  
  50.     }         
  51.     privatevoid findAndModifyButton()  
  52.     {  
  53.         // 測試JAVA的NDK呼叫
  54.         Button btn01 = (Button)findViewById(R.id.Button01);  
  55.         btn01.setOnClickListener(new Button.OnClickListener()  
  56.         {  
  57.                 publicvoid onClick(View v)  
  58.              {        
  59.                 TextView tv = (TextView)findViewById(R.id.tv01);  
  60.                 tv.setText(stringFromJNI());              
  61.                 showMessage(JniDemoActivity.this,"JNI test1", stringFromJNI());  
  62.             }  
  63.         });  
  64.         // 測試C/C++中對JAVA函式的靜態回撥
  65.         Button btn02 = (Button)findViewById(R.id.Button02);  
  66.         btn02.setOnClickListener(new Button.OnClickListener()  
  67.         {  
  68.                 publicvoid onClick(View v)  
  69.              {  
  70.                 int ret =jniStaticShowMessage(JniDemoActivity.this,"JNI test2""test static callback Message");  
  71.                 TextView tv = (TextView)findViewById(R.id.tv01);  
  72.                   if(ret == 0)  
  73.                 {  
  74.                     tv.setText("test JNI static callback successed");                        
  75.                 }  
  76.                 else
  77.                 {  
  78.                     tv.setText("test JNI static callback fialed");  
  79.                 }  
  80.                 }  
  81.     });  
  82.     // 測試例項中C/C++中對JAVA類的函式的呼叫
  83.     Button btn03 = (Button)findViewById(R.id.Button03);  
  84.     btn03.setOnClickListener(new Button.OnClickListener()  
  85.     {  
  86.         publicvoid onClick(View v)  
  87.         {  
  88.             strTest = " [message has changed now]";  
  89.             int ret = jniShowMessage(JniDemoActivity.this,"JNI test3""test callback in current instance");  
  90.             TextView tv = (TextView)findViewById(R.id.tv01);              
  91.            if(ret == 0)  
  92.             {  
  93.                tv.setText("test JNI callback successed");                        
  94.             }  
  95.             else
  96.             {  
  97.                tv.setText("test JNI callback fialed");  
  98.             }  
  99.         }  
  100.     });  
  101.     // 測試建立新例項C/C++對JAVA類的函式的呼叫
  102.     Button btn04 = (Button)findViewById(R.id.Button04);  
  103.     btn04.setOnClickListener(new Button.OnClickListener()  
  104.     {  
  105.         publicvoid onClick(View v)  
  106.         {  
  107.             strTest = " [message has changed now]";  
  108.             int ret = jniInstanceShowMessage(JniDemoActivity.this,"JNI test4""test callback in new instance");  
  109.             TextView tv = (TextView)findViewById(R.id.tv01);              
  110.             if(ret == 0)  
  111.             {  
  112.                tv.setText("test JNI new instance successed");                           
  113.             }  
  114.             else
  115.             {  
  116.                tv.setText("test JNI new instance fialed");  
  117.             }  
  118.         }  
  119.     });  
  120.     }    
  121. }  
package study.jnidemo; 

import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.widget.Button;
import android.view.View;
import android.widget.TextView;
import android.content.Context;
import android.content.DialogInterface; 

publicclass JniDemoActivityextends Activity {    

    public StringstrTest =" [initial message]";           

    /** Called when the activity is first created. */
    @Override
    publicvoid onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);       

        findAndModifyButton();
    }

    public String getTestString()
    {
    	returnstrTest;
    }   

    // 測試JAVA的NDK呼叫
    publicnative String stringFromJNI();    

    // 測試C/C++中對JAVA函式的靜態回撥
    publicnativestaticint jniStaticShowMessage(Context ctx, String strTitle, String strMessage);    

    // 測試例項中C/C++中對JAVA類的函式的呼叫
    publicnativeint jniShowMessage(Context ctx, String strTitle, String strMessage);    

    // 測試建立新例項C/C++對JAVA類的函式的呼叫
    publicnativeint jniInstanceShowMessage(Context ctx, String strTitle, String strMessage);    

    static {
        System.loadLibrary("demo-jni");
    }    

    staticint staticShowMessage(Context ctx, String strTitle, String strMessage)
    {   
    	AlertDialog.Builder builder = new AlertDialog.Builder(ctx);   
    	builder.setTitle(strTitle);
    	builder.setMessage(strMessage);
    	builder.setPositiveButton("確定",
         new DialogInterface.OnClickListener(){

        	   public void onClick(DialogInterface dialog,int whichButton){	            

        	   }
    	});
    	builder.show();    
    	return 0;

    }   

    publicint showMessage(Context ctx, String strTitle, String strMessage)
    {
    	returnstaticShowMessage(ctx, strTitle, strMessage);
    }       

    privatevoid findAndModifyButton()
    {
    	// 測試JAVA的NDK呼叫
    	Button btn01 = (Button)findViewById(R.id.Button01);
    	btn01.setOnClickListener(new Button.OnClickListener()
    	{
        	    publicvoid onClick(View v)
             {      
            	TextView tv = (TextView)findViewById(R.id.tv01);
            	tv.setText(stringFromJNI());            

            	showMessage(JniDemoActivity.this,"JNI test1", stringFromJNI());
            }
    	});

    

    	// 測試C/C++中對JAVA函式的靜態回撥
    	Button btn02 = (Button)findViewById(R.id.Button02);
    	btn02.setOnClickListener(new Button.OnClickListener()
    	{

        	    publicvoid onClick(View v)
             {
            	int ret =jniStaticShowMessage(JniDemoActivity.this,"JNI test2", "test static callback Message");
            	TextView tv = (TextView)findViewById(R.id.tv01);

                  if(ret == 0)
            	{
               	    tv.setText("test JNI static callback successed");                      
            	}
            	else
            	{

               	    tv.setText("test JNI static callback fialed");
            	}
        	    }

    });
 

    // 測試例項中C/C++中對JAVA類的函式的呼叫
    Button btn03 = (Button)findViewById(R.id.Button03);
    btn03.setOnClickListener(new Button.OnClickListener()
    {
        publicvoid onClick(View v)
        {
            strTest = " [message has changed now]";
            int ret = jniShowMessage(JniDemoActivity.this,"JNI test3", "test callback in current instance");
            TextView tv = (TextView)findViewById(R.id.tv01);            

           if(ret == 0)
            {
               tv.setText("test JNI callback successed");                      
            }
            else
            {
               tv.setText("test JNI callback fialed");
            }
        }
    });

    
    // 測試建立新例項C/C++對JAVA類的函式的呼叫
    Button btn04 = (Button)findViewById(R.id.Button04);
    btn04.setOnClickListener(new Button.OnClickListener()
    {
        publicvoid onClick(View v)
        {
            strTest = " [message has changed now]";
            int ret = jniInstanceShowMessage(JniDemoActivity.this,"JNI test4", "test callback in new instance");
            TextView tv = (TextView)findViewById(R.id.tv01);            

            if(ret == 0)
            {
               tv.setText("test JNI new instance successed");                         
            }
            else
            {
               tv.setText("test JNI new instance fialed");
            }
        }
    });
    }  

}

C程式碼 demo-jni.cpp

[cpp] view plaincopyprint?
  1. #include<string.h>
  2. #include<jni.h>
  3. // 載入此動態庫時系統自動首先載入
  4. jint JNI_OnLoad(JavaVM* vm, void *reserved)  
  5. {  
  6.     JNIEnv *env;  
  7.     if((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK)  
  8.     {  
  9.        return -1;  
  10.     }  
  11.     return JNI_VERSION_1_4;  
  12. }   
  13. jstring  
  14. Java_study_jnidemo_JniDemoActivity_stringFromJNI( JNIEnv* env,jobject thiz )  
  15. {  
  16.     return (*env)->NewStringUTF(env,"JniDemo, Hello from JNI!");  
  17. }  
  18. jstring  
  19. combine_jstring(JNIEnv* env, jstring str1, jstring str2)  
  20. {  
  21.     jboolean b_ret;  
  22.     constchar *s1 = (*env)->GetStringUTFChars(env, str1, &b_ret);  
  23.     constchar *s2 = (*env)->GetStringUTFChars(env, str2, &b_ret);  
  24.     int n1 = strlen(s1);  
  25.     int n2 = strlen(s2);  
  26.     char *new_str = (char *)malloc(n1+n2+1);  
  27.     memset(new_str, 0, n1+n2+1);  
  28.     strcat(new_str, s1);  
  29.     strcat(new_str, s2);  
  30.     jstring ret_str = (*env)->NewStringUTF(env,(constchar *)new_str);  
  31.     free(new_str);  
  32.     return ret_str;  
  33. }  
  34. jint  
  35. Java_study_jnidemo_JniDemoActivity_jniStaticShowMessage(JNIEnv* env, jobject thiz,  
  36.        jobject ctx, jstring strTitle, jstring strMessage)  
  37. {  
  38.     jclass cls = (*env)->FindClass(env, "study/jnidemo/JniDemoActivity");  
  39. //  jclass cls = (*env)->GetObjectClass(env, thiz);
  40.     if(cls != NULL)  
  41.     {  
  42.        jmethodID id = (*env)->GetStaticMethodID(env, cls,  
  43.              "staticShowMessage",