Android NDK开发(2)----- JNI多线程
来源:互联网 发布:西恩潘 知乎 编辑:程序博客网 时间:2024/05/22 06:42
一、概述
JNI编程和Linux上的C/C++编程还是挺相似的,每次java调用JNI中的函数时都会传入有关JVM的一些参数(如JNIEnv,jobject),每次JNI回调java中的方法时都要通过JVM的有关参数来实现,当在JNI中涉及到多线程的话还是有一些不一样的地方,就是要在子线程函数里使用AttachCurrentThread()和DetachCurrentThread()这两个函数,在这两个函数之间加入回调java方法所需要的代码。
二、要求
掌握JNI多线程编程的方法。
三、实现
新建工程MyThread,修改main.xml文件,在里面只有一个Button,如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:orientation="vertical" > 6 7 <Button 8 android:id="@+id/button" 9 android:layout_width="fill_parent"10 android:layout_height="wrap_content"11 android:text="启动JNI线程"12 />13 14 </LinearLayout>
修改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 @Override15 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 @Override26 public void onClick(View v) 27 {28 // TODO Auto-generated method stub29 //调用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 static49 {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 515 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)
使用ndk-build成功编译出动态库后,运行该程序:
并点击2下按钮,LogCat输出如下:
0 0
- Android NDK开发(2)----- JNI多线程
- Android NDK开发(2)----- JNI多线程
- Android NDK开发(2)----- JNI多线程
- Android NDK开发(2)----- JNI多线程
- Android NDK开发(2)----- JNI多线程
- Android NDK开发(2)----- JNI多线程
- Android NDK开发(2)----- JNI多线程
- Android NDK开发----- JNI多线程
- Android NDK(JNI)开发
- Android NDK(八):JNI多线程
- Android JNI/NDK 开发
- android-ndk-r4下jni开发2
- android studio2.2初探ndk jni开发
- Android NDK(JNI)开发入门
- Android studio JNI(NDK) 开发
- Android开发之NDK(JNI)
- Android JNI/NDK开发(一)NDK真的很难吗?
- Android NDk-JNi开发(一)NDK环境变量的配置
- 《大话设计模式》 -- 14.抽象工厂模式
- JDK环境变量设置详解
- IE对http1.1 不支持201状态码
- C++的64位整数[原]by 赤兔
- 《汇编语言》王爽版重点摘要-----第五章
- Android NDK开发(2)----- JNI多线程
- jstat命令用法
- STL之map容器
- HDU4442
- ZOJ 3261 Connections in Galaxy War 并查集
- LPC1788 EMWIN
- RLwrap的安装和配置
- HDU 1157(水题)
- replace into用法