Android NDK开发----- JNI多线程
一、概述
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 @Override
15 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 @Override
26 public void onClick(View v)
27 {
28 // TODO Auto-generated method stub
29 //调用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 static
49 {
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 5
15
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输出如下:

Android NDK开发----- JNI多线程的更多相关文章
- Android NDK开发 JNI操作java构造方法,普通方法,静态方法(七)
Android NDK开发 JNI操作java普通.静态.构造方法 1.Jni实例化一个Java类的实例jobject 1.通过FindClas( ),获取Java类的的jclass 2.通过GetM ...
- Android NDK开发 Jni中打日志LOG(二)
HelloJni.c文件中,加入头文件和函数声明.最终文件如下: #include <jni.h> #include <string.h> #include<androi ...
- Android NDK开发 Jni中Debug(三)
下载LLDB 配置Android Native - Debugger 调式结果如下 #include <jni.h> #include <string.h> #include& ...
- Android NDK开发 JNI类型签名和方法签名(六)
在Java存在两种数据类型: 基本类型 和 引用类型 ,大家都懂的 . 在JNI的世界里也存在类似的数据类型,与Java比较起来,其范围更具严格性,如下: 1.primitive types ---- ...
- Android NDK开发Hello Word!
在之前的博客中已经为大家介绍了,如何在win环境下配置DNK程序,本篇我将带大家实现一个简单的Hello jni程序,让大家真正感受一下NDK开发的魅力.这里我们选择使用C+JAVA开发Android ...
- Android NDK开发初识
神秘的Android NDK开发往往众多程序员感到兴奋,但又不知它为何物,由于近期开发应用时,为了是开发的.apk文件不被他人解读(反编译),查阅了很多资料,其中有提到使用NDK开发,怀着好奇的心理, ...
- Android NDK开发
Android NDK 开发教程(极客学院) 一.Android NDK环境搭建 使用最新ndk,直接抛弃cygwin,以前做Android的项目要用到NDK就必须要下载NDK,下载安装Cygwin( ...
- Android NDK 开发(四)java传递数据到C【转】
转载请注明出处:http://blog.csdn.net/allen315410/article/details/41845701 前面几篇文章介绍了Android NDK开发的简单概念.常见错误及处 ...
- Android NDK 开发(三)--常见错误锦集合Log的使用【转】
转载请注明出处:http://blog.csdn.net/allen315410/article/details/41826511 Android NDK开发经常因某些因素会出现一些意想不到的错误, ...
随机推荐
- mysql协议简析
前言 如果要在命令行中连接mysql,最常用的便是 mysql -u root -p 这样指定用户名和密码 当然还可以使用远程连接 mysql -h 127.0.0.1 -u root -p 还有一种 ...
- [转]SharePoint 2010 Powershell Feature Cmdlets
In this installment its time to look at the various cmdlets that have to do with Features. Of course ...
- Unity Shader基础
Unity Shader基础 先上代码,代码一般是这样的. void Initialization(){ //先从硬盘加载代码再加载到GPU中 string vertexShaderCode = Lo ...
- 选择器(UIPickerView)
Apple提供了两种形式的选择器:日期选择器(UIDatePicker)与自定义选择器(UIPickerView). 当用户使用日期选择器选定一个时间后,调用datePickerID.date可以直接 ...
- T-sql 行转列,数据库查询分页
1 USE [APS_Future_FT] 2 GO 3 /****** Object: StoredProcedure [dbo].[A_CrudePrice] Script Date: 2013/ ...
- vim自动补全插件YouCompleteMe的安装及配置
原文地址: http://blog.csdn.net/shixuehancheng/article/details/46289811
- 【WIN10】Storyboard動畫板
源碼下載:http://yunpan.cn/cFJR5zcMNtBq6 访问密码 ac7a 使用Storyboard可以實現動畫效果. 1.仿照WINDOWS系統安裝時的等待畫面,不停更換背景顏色 ...
- java 线程 wait join sleep yield notify notifyall synchronized
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 休息方法 : 在指定时间内 让该线程 暂停, 不会释放 锁标志. 等待方法: 让 该 线 ...
- maven搭建企业级多模块项目
1.创建一个maven项目 选择pom 完成 2.创建模块 项目右键选择module,创建模块.创建子模块 其余的打包时都为jar 地址:https://github.com/LeviFromCN/m ...
- USACO 2017 FEB Platinum nocross DP
题目大意 上下有两个长度为n.位置对应的序列A.B,其中数的范围均为1~n.若abs(A[i]-B[j]) <= 4,则A[i]与B[j]间可以连一条边.现要求在边与边不相交的情况下的最大的连边 ...