Java中使用线程特别简单,实现Runnable接口 或者 继承Thread.
NDK中使用线程可以在Activity中直接调用java线程,也可以通过JNI启动线程,这个线程源于POSIX中的线程库。
需要使用POSIX中pthread
头文件
如果启动了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,"","()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.");
}
}