JNI Introduce

References:
http://blog.csdn.net/banketree/article/details/40535325
百度百科:http://baike.baidu.com/link?url=G_C-p8YK5fnYffQFRure1sr80yBHmmP5VMMyKbGPzWiGWhKldWXfoLaQKEwJcS-vP_i9dLg79rSrni69wJ_ima
百度文庫:http://wenku.baidu.com/link?url=09Ca0f6iD-jgb4c1m5Uao8bL_z_vYVGs39k7cE5NZwACaVYNpOZJH7NoHloAh0sABFU9j_haF0erMBPKs6VfXQNJ7EI92AETUomwvWvylXK

http://wenku.baidu.com/view/107c3d37b90d6c85ec3ac671.html?re=view

  1. JNI Introduce
    –>你可以使用JNI來實現“本地方法”(native methods),並在JAVA程序中調用它們。
    –>JNI支持一個“調用接口”(invocation interface),它允許你把一個JVM嵌入到本地程序中。本地程序可以鏈接一個實現了JVM的本地庫,然後使用“調用接口”執行JAVA語言編寫的軟件模塊。
  2. JNIEnv && JavaVM
    –>JavaVM : JavaVM 是 Java虛擬機在 JNI 層的代表, JNI 全局只有一個
    –>JNIEnv : JavaVM 在線程中的代表, 每個線程都有一個, JNI 中可能有很多個 JNIEnv;
    這裏寫圖片描述
  3. JNI_OnLoad()與JNI_OnUnload()
    當Android的VM(Virtual Machine)執行到System.loadLibrary()函數時,首先會去執行C組件裏的JNI_OnLoad()函數。它的用途有二:
    (1)告訴VM此C組件使用那一個JNI版本。如果你的.so檔沒有提供JNI_OnLoad()函數,VM會默認該.so檔是使用最老的JNI 1.1版本。由於新版的JNI做了許多擴充,如果需要使用JNI的新版功能,例如JNI 1.4的java.nio.ByteBuffer,就必須藉由JNI_OnLoad()函數來告知VM。
    (2)由於VM執行到System.loadLibrary()函數時,就會立即先呼叫JNI_OnLoad(),所以C組件的開發者可以藉由JNI_OnLoad()來進行C組件內的初期值之設定(Initialization) 。
  4. JNI 調用示例:
    http://www.cnblogs.com/bastard/archive/2012/05/19/2508913.html
  5. JNI AttacheThread示例:
    http://www.2cto.com/kf/201203/123575.html
    修改MyThreadActivity.java文件,實現按鈕的監聽,在裏面調用JNI中的函數來啓動JNI中的線程,比較簡單,如下:
 1 package com.nan.thread;
 2
 3 import android.app.Activity;
 4 import android.os.Bundle;
 5 import android.util.Log;
 6 import android.view.View;
 7 import android.widget.Button;
 8
 9 public class MyThreadActivity extends Activity
10 {
11     private Button mButton = null;
12    
13     /** Called when the activity is first created. */
14     @Override
15     public void onCreate(Bundle savedInstanceState)
16     {
17         super.onCreate(savedInstanceState);
18         setContentView(R.layout.main);
19        
20         mButton = (Button)this.findViewById(R.id.button);
21         //按鈕監聽
22         mButton.setOnClickListener(new View.OnClickListener()
23         {
24            
25             @Override
26             public void onClick(View v)
27             {
28                 // TODO Auto-generated method stub
29                 //調用JNI中的函數來啓動JNI中的線程
30                 mainThread();
31                
32             }
33         });
34         //初始化JNI環境
35         setJNIEnv();
36     }
37         
38     //由JNI中的線程回調
39     private static void fromJNI(int i)
40     {
41         Log.v("Java------>", ""+i);
42     }
43    
44     //本地方法
45     private native void mainThread();
46     private native void setJNIEnv();
47    
48     static
49     {
50         //加載動態庫
51         System.loadLibrary("JNIThreads");
52     }
53
54 }

編寫JNI_Thread.c文件,在mainThread()函數裏啓動5個子線程,在子線程函數裏回調java中的靜態方法fromJNI()來輸出當前子線程是第幾個被啓動的線程。完整的內容如下:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<unistd.h>
 4 #include<pthread.h>
 5
 6 #include<jni.h>
 7 #include<android/log.h>
 8
 9 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
10 #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
11 #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "native-activity", __VA_ARGS__))
12
13 //線程數
14 #define NUMTHREADS 5
15
16 //全局變量
17 JavaVM *g_jvm = NULL;
18 jobject g_obj = NULL;
19
20
21 void *thread_fun(void* arg)
22 {
23     JNIEnv *env;
24     jclass cls;
25     jmethodID mid;
26
27     //Attach主線程
28     if((*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL) != JNI_OK)
29     {
30         LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
31         return NULL;
32     }
33     //找到對應的類
34     cls = (*env)->GetObjectClass(env,g_obj);
35     if(cls == NULL)
36     {
37         LOGE("FindClass() Error.....");
38         goto error;
39     }
40     //再獲得類中的方法
41     mid = (*env)->GetStaticMethodID(env, cls, "fromJNI", "(I)V");
42     if (mid == NULL)
43     {
44         LOGE("GetMethodID() Error.....");
45         goto error; 
46     }
47     //最後調用java中的靜態方法
48         (*env)->CallStaticVoidMethod(env, cls, mid ,(int)arg);
49    
50
51 error:   
52     //Detach主線程
53     if((*g_jvm)->DetachCurrentThread(g_jvm) != JNI_OK)
54     {
55         LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
56     }
57    
58
59     pthread_exit(0);
60 }
61
62 //由java調用以創建子線程
63 JNIEXPORT void Java_com_nan_thread_MyThreadActivity_mainThread( JNIEnv* env, jobject obj)
64 {
65     int i;
66     pthread_t pt[NUMTHREADS];
67    
68     for (i = 0; i < NUMTHREADS; i++)
69         //創建子線程
70         pthread_create(&pt[i], NULL, &thread_fun, (void *)i);
71 }
72
73
74 //由java調用來建立JNI環境
75 JNIEXPORT void Java_com_nan_thread_MyThreadActivity_setJNIEnv( JNIEnv* env, jobject obj)
76 {
77     //保存全局JVM以便在子線程中使用
78     (*env)->GetJavaVM(env,&g_jvm);
79     //不能直接賦值(g_obj = obj)
80     g_obj = (*env)->NewGlobalRef(env,obj);
81 }
82
83
84 //當動態庫被加載時這個函數被系統調用
85 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
86 {
87     JNIEnv* env = NULL;
88     jint result = -1;   
89
90     //獲取JNI版本
91     if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK)
92     {
93         LOGE("GetEnv failed!");
94             return result;
95     }
96
97     return JNI_VERSION_1_4;
98 }

Android.mk

1 LOCAL_PATH := $(call my-dir)
 2
 3 include $(CLEAR_VARS)
 4
 5 LOCAL_MODULE    := JNIThreads
 6 LOCAL_SRC_FILES := JNI_Threads.c
 7
 8 LOCAL_LDLIBS    := -llog
 9
10 include $(BUILD_SHARED_LIBRARY)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章