注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

linux 学习

 
 
 

日志

 
 

JNI多线程回调JAVA函数  

2012-07-30 13:50:46|  分类: 安卓 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、概述
      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输出如下:

  \


 

  评论这张
 
阅读(4552)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017