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."); } }