Java中使用線程特別簡單,實現Runnable介面 或者 繼承Thread.
NDK中使用線程可以在Activity中直接調用java線程,也可以通過JNI啟動線程,這個線程源於POSIX中的線程庫。
需要使用POSIX中pthread
標頭檔<pthread.h>
如果啟動了Posix線程,是無法與Android Java層互動的,主要是因為POSIX線程中無法直接調用JNIEnv 。
因此我們需要先把native thread與JVM關聯上,這樣既可獲得JNIEnv。沒有JNIEnv是無法回調JAVA層的方法。
編寫一個Activity 只是列印一個語句Toast
public class MainActivity extends Activity {static {System.loadLibrary("ndk-thread");}public static MainActivity instance;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.start).setOnClickListener(new OnClickListener() {public void onClick(View arg0) {JNI.startThreadJNI(); //JNI Native 方法,啟動線程}});instance = this;}public void showMsg(final String msg) {Log.d("showMsg","msg:" + msg);MainActivity.instance.runOnUiThread(new Runnable(){@Overridepublic void run() {Toast.makeText(instance, msg, Toast.LENGTH_SHORT).show(); //回調彈出訊息}});}}
JNI.java
public class JNI { public JNI() { } public native static void startThreadJNI();}
建立一個Callback.java 用來回調Activity的showMsg方法
public class Callback {public void setMsg(String msg) {MainActivity.instance.showMsg(msg);}public Callback() {}}
在JNI_OnLoad方法中 我們能擷取到JVM對象,這個方法是有架構自動執行的。在JNI.h標頭檔中有原型。
JavaVM* jvm1 = NULL;jobject obj1 = NULL;jmethodID mid1 = NULL;jint JNI_OnLoad (JavaVM* vm, void* reserved){jvm1 = vm;return JNI_VERSION_1_4;}void *run_task(void *args) { //線程需要執行的東西JNIEnv* env = NULL; int n = (*jvm1)->AttachCurrentThread(jvm1,&env, NULL); //從jvm中擷取到JNIEnv if (n == 0) { jstring msg = (*env)->NewStringUTF(env,"Yes Thread Running."); (*env)->CallVoidMethod(env, obj1, mid1, msg); //回調JAVA層Callback類中的方法 (*env)->DeleteGlobalRef(env,obj1); //刪除引用 (*jvm1)->DetachCurrentThread(jvm1); //這個一定要調用,否則報錯,意在取消線程與jvm關聯 } LOGI("44");}void init_instance(JNIEnv *env) { LOGI("instance."); jclass jz1 = (*env)->FindClass(env,"com/birds/android/ndk/thread1/Callback"); jmethodID mid = (*env)->GetMethodID(env,jz1,"<init>","()V"); jobject myobj = (*env)->NewObject(env,jz1,mid); obj1 = (*env)->NewGlobalRef(env,myobj); LOGI("OK Instance Done."); mid1 = (*env)->GetMethodID(env, jz1, "setMsg", "(Ljava/lang/String;)V");}
編寫JNI層代碼。直接寫C代碼
JNIEXPORT void JNICALL Java_com_birds_android_ndk_thread1_JNI_startThreadJNI (JNIEnv *env, jclass jclas) { init_instance(env);//主要是準備一些對象執行個體化,Callback執行個體化 pthread_t thread1; int n = pthread_create(&thread1,NULL,run_task,NULL);//啟動線程,調用run_task方法 if (n != 0) { //線程建立失敗 jclass exceptionClazz = (*env)->FindClass(env, "java/lang/RuntimeException"); (*env)->ThrowNew(env,exceptionClazz, "create thread error."); }}