NDK 5 使用POSIX線程

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;

	@Override
	protected 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(){
			@Override
			public 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.");

    }


}












發佈了64 篇原創文章 · 獲贊 5 · 訪問量 32萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章