Android下的JNI创建多线程的方法

简介: Android下的JNI创建多线程的方法

本文参考了http://www.cnblogs.com/lknlfy/archive/2012/03/16/2400786.html这篇博文,加了点自己的东西

废话不多说,贴代码上来

java的代码:

package com.example.jni_thread_demo;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
public class JNI_ThreadActivity extends Activity {
  private Button mButton = null;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_jni__thread);
    mButton = (Button)findViewById(R.id.button);
    mButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        // 调用JNI中的函数来启动JNI中的线程
        mainThread();
      }
    });
    // 初始化JNI环境
    setJNIEnv();
  }
  //由JNI中的线程回调类方法
  private static void fromJNI(int i)
  {
    Log.v("Java---------->", ""+i);
  }
       //自己定义的线程回调成员方法
  private void From_JNI_Again (int i)
  {
    Log.v("Java_object------------>", ""+i);
  }
  // 本地方法
  private native void mainThread();
  private native void setJNIEnv();
  static
  {
    System.loadLibrary("JNIThread");
  }
}

jni中的代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h>
#include<assert.h>
#include<jni.h>
#include<android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "jni_thread", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "jni_thread", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "jni_thread", __VA_ARGS__))
// 线程数
#define NUMTHREADS 5
// 指定要注册的类
#define JNIREG_CLASS "com/example/jni_thread_demo/JNI_ThreadActivity"
// 全局变量
JavaVM* g_jvm = NULL;
jobject g_obj = NULL;
void* thread_fun(void* arg)
{
  JNIEnv *env;
  jclass cls;
  jmethodID mid, mid1;
  // Attach主线程
  if((*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL) != JNI_OK)
  {
    LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
    return NULL;
  }
  // 找到对应的类
  cls = (*env)->GetObjectClass(env, g_obj);
  if(cls == NULL)
  {
    LOGE("FindClass() Error ......");
    goto error;
  }
  // 再获得类中的方法
  mid = (*env)->GetStaticMethodID(env, cls, "fromJNI", "(I)V");
  if(mid == NULL)
  {
    LOGE("GetStaticMethodID() Error ......");
    goto error;
  }
  // 最后调用java中的静态方法
  (*env)->CallStaticVoidMethod(env, cls, mid, (int)arg);
  //获得类中的“成员”方法
  mid1 = (*env)->GetMethodID(env, cls, "From_JNI_Again", "(I)V");
  if(mid == NULL)
  {
    LOGE("GetMethodID() Error ......");
    goto error;
  }
  // 最后调用类中“成员”方法
  (*env)->CallVoidMethod(env, g_obj, mid1, (int)arg);
  //错误处理代码
  error:
  //Detach主线程
  if((*g_jvm)->DetachCurrentThread(g_jvm) != JNI_OK)
  {
    LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
  }
  pthread_exit(0);
}
/*
 * Class:     com_example_jni_thread_demo_JNI_ThreadActivity
 * Method:    mainThread
 * Signature: ()V
 */
/*不用JNI_OnLoad时的复杂命名方式
JNIEXPORT void JNICALL Java_com_example_jni_1thread_1demo_JNI_1ThreadActivity_mainThread
  (JNIEnv *env, jobject obj)
{
  int i;
  pthread_t pt[NUMTHREADS];
  for(i=0; i<NUMTHREADS; i++)
  {
    // 创建线程,并指明调用的函数
    pthread_create(&pt[i], NULL, &thread_fun, (void*)i);
  }
}*/
/*
 * Class:     com_example_jni_thread_demo_JNI_ThreadActivity
 * Method:    setJNIEnv
 * Signature: ()V
 *//*不用JNI_OnLoad时的复杂命名方式
JNIEXPORT void JNICALL Java_com_example_jni_1thread_1demo_JNI_1ThreadActivity_setJNIEnv
  (JNIEnv *env, jobject obj)
{
  // 保存全局JVM以便在子线程中使用
  (*env)->GetJavaVM(env, &g_jvm);
  // 不能直接赋值(g_obj = ojb)
  g_obj = (*env)->NewGlobalRef(env, obj);
}*/
JNIEXPORT void JNICALL native_mainThread(JNIEnv *env, /*jclass clazz*/ jobject obj)// 使用jclass和jobject都可以
{
  LOGI("native_mainThread");
  int i;
  pthread_t pt[NUMTHREADS];
  for(i=0; i<NUMTHREADS; i++)
  {
    // 创建线程,并指明调用的函数,注意只接收一个参数i作为thread_fun的参数,后面会介绍怎么传多个参数
    pthread_create(&pt[i], NULL, &thread_fun, (void*)i);
  }
}
JNIEXPORT void JNICALL native_setJNIEnv(JNIEnv *env, /*jclass obj*/ jobject obj)// 使用jclass和jobject都可以
{
  LOGI("native_setJNIEnv");
  // 保存全局JVM以便在子线程中使用
  (*env)->GetJavaVM(env, &g_jvm);
  // 不能直接赋值(g_obj = ojb)
  g_obj = (*env)->NewGlobalRef(env, obj);
}
/**
* Table of methods associated with a single class.
*/
static JNINativeMethod gMethods[] =
{
    {"mainThread", "()V", (void*)native_mainThread }, // 绑定:注意千万签名结尾不能加分号!!!!!!
    {"setJNIEnv", "()V", (void*)native_setJNIEnv },
};
/*
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
  JNINativeMethod* gMethods, int numMethods)
{
  jclass clazz;
  clazz = (*env)->FindClass(env, className);
  if (clazz == NULL)
  {
    return JNI_FALSE;
  }
  if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0)
  {
    return JNI_FALSE;
  }
  return JNI_TRUE;
}
/*
* Register native methods for all classes we know about.
*/
static int registerNatives(JNIEnv* env)
{
  if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,
      sizeof(gMethods) / sizeof(gMethods[0])))
  return JNI_FALSE;
  return JNI_TRUE;
}
/*
* Set some test stuff up.
*
* Returns the JNI version on success, -1 on failure.
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
  JNIEnv* env = NULL;
  jint result = -1;
  if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    LOGE("GetEnv failed!");
    return -1;
  }
  //===========================================
  assert(env != NULL);
  if (!registerNatives(env))
  {// 注册本地方法
    return -1;
  }
  //===========================================
  /* success -- return valid version number */
  result = JNI_VERSION_1_4;
  return result;
}

Android.mk文件中的代码:

LOCAL_PATH :=$(call my-dir)
include $(CLEAR_VAR)
LOCAL_MODULE := JNIThread
LOCAL_SRC_FILES := JNI_Thread.c
LOCAL_MODULE_FILENAME := libJNIThread//如果报LOCAL_MODULE_FILENAME的错的话,需要加上这句话
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)

如何给线程函数传递多个参数:

涉及多参数传递给线程的,都需要使用结构体将参数封装后,将结构体指针传给线程
定义一个结构体

struct mypara
{
  var para1;//参数1
  var para2;//参数2
}

将这个结构体指针,作为void *形参的实际参数传递

struct mypara pstru;
pthread_create(&ntid, NULL, thr_fn,& (pstru));

函数中需要定义一个mypara类型的结构指针来引用这个参数

void *thr_fn(void *arg)
{
  mypara *pstru;
  pstru = (* struct mypara) arg;
  pstru->para1;//参数1
  pstru->para2;//参数2  
}

如何多线程同步通信:

至于多个线程是怎么进行同步通信的,可以参考这篇博文

http://blog.csdn.net/chenghongyue/article/details/8124976

目录
相关文章
|
3月前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
4月前
|
API Android开发 iOS开发
深入探索Android与iOS的多线程编程差异
在移动应用开发领域,多线程编程是提高应用性能和响应性的关键。本文将对比分析Android和iOS两大平台在多线程处理上的不同实现机制,探讨它们各自的优势与局限性,并通过实例展示如何在这两个平台上进行有效的多线程编程。通过深入了解这些差异,开发者可以更好地选择适合自己项目需求的技术和策略,从而优化应用的性能和用户体验。
|
5月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
153 15
Android 系统缓存扫描与清理方法分析
|
5月前
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【10月更文挑战第11天】本文探讨了如何在Kotlin中实现高效的多线程方案,特别是在Android应用开发中。通过介绍Kotlin协程的基础知识、异步数据加载的实际案例,以及合理使用不同调度器的方法,帮助开发者提升应用性能和用户体验。
102 4
|
6月前
|
ARouter 测试技术 API
Android经典面试题之组件化原理、优缺点、实现方法?
本文介绍了组件化在Android开发中的应用,详细阐述了其原理、优缺点及实现方式,包括模块化、接口编程、依赖注入、路由机制等内容,并提供了具体代码示例。
95 2
|
6月前
|
Java Android开发 UED
🧠Android多线程与异步编程实战!告别卡顿,让应用响应如丝般顺滑!🧵
在Android开发中,为应对复杂应用场景和繁重计算任务,多线程与异步编程成为保证UI流畅性的关键。本文将介绍Android中的多线程基础,包括Thread、Handler、Looper、AsyncTask及ExecutorService等,并通过示例代码展示其实用性。AsyncTask适用于简单后台操作,而ExecutorService则能更好地管理复杂并发任务。合理运用这些技术,可显著提升应用性能和用户体验,避免内存泄漏和线程安全问题,确保UI更新顺畅。
198 5
|
6月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
198 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
算法 Java Android开发
Android模拟多线程下载
Android模拟多线程下载
93 0
|
Android开发 缓存
android --多线程下载
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/50971687 多线程下载文件的过程是:    (1)首先获得下载文件的长度,然后设置本地文件的长度。
699 0

热门文章

最新文章

  • 1
    【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
    66
  • 2
    android FragmentManager 删除所有Fragment 重建
    26
  • 3
    Android实战经验之Kotlin中快速实现MVI架构
    42
  • 4
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    42
  • 5
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    46
  • 6
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    161
  • 7
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    55
  • 8
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    73
  • 9
    Android历史版本与APK文件结构
    183
  • 10
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    54