我的编程空间,编程开发者的网络收藏夹
学习永远不晚

基于Android Studio NDK开发

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

基于Android Studio NDK开发

1.  开发环境配置

Android Studio3.0.1
android-ndk-r13
gradle插件: classpath 'com.android.tools.build:gradle:3.0.1'
gradle:distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
  插件:
  Android NDK Support
  Cmake simple highlighter
  SDk Tools :LLDB  
 博主家里的就是这样,写c++有提示,但是公司开发环境类似,写C++木有提示??,没有提示???

2. NKD字符串操作:

   MainActivity申明:

 
    public native String stringFromJNI();

native-lib.cpp 实现


#include 
#include 
#include 
#include 
extern "C"
JNIEXPORT jstring

#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "JNI", __VA_ARGS__)
// 字符串
JNICALL
Java_lanya_denganzhi_com_ndk_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject ) {
    // char*  =》jstring
    std::string hello = "Hello from C++";
    jstring  str=env->NewStringUTF(hello.c_str());
    // jstring->char*
    const char* s= env->GetStringUTFChars(str,0);
    LOGE("转化的char*是:%s",s);
    env->ReleaseStringUTFChars(str,s);
    return str;
}
3.数组操作

 public void testArr(View view){
        int a[]={1,2};
        arrayEncode(a);
         Toast.makeText(MainActivity.this, Arrays.toString(a),Toast.LENGTH_SHORT).show();
    }
 
    public native void arrayEncode(int[] arr);

// 数组
extern "C"
JNIEXPORT void JNICALL
Java_lanya_denganzhi_com_ndk_MainActivity_arrayEncode(JNIEnv *env, jobject instance,
                                                      jintArray arr_) {
    
    jint *arr = env->GetIntArrayElements(arr_, NULL);
    int length = env->GetArrayLength( arr_);
    for(int i=0;iReleaseIntArrayElements(arr_, arr, 0);
}
4.  参数传递对象,  C调用Java  [Java反射使用]

package lanya.denganzhi.com.ndk;
import android.util.Log;

public class Bean {
    private int i;
    public int getI() {
        Log.e("denganzhi","invoke-java-getI");
        return i;
    }
    public void setI(int i) {
        Log.e("denganzhi","invoke-java-setI");
        this.i = i;
    }
    public static void printInfo(String msg){
        Log.e("denganzhi1",msg+"");
    }
}

package lanya.denganzhi.com.ndk;

public class Bean2 {
    private int i;
    public Bean2(int i) {
        this.i = i;
    }
    public Bean2() {
    }
}

 声明Native方法:


    public void testArr(View view){
        Bean bean=new Bean();
        passObject(bean,"test---bean");
    }
     
    public native void passObject(Bean bean, String string);

C++调用: 


// instance: java中MainActivity    bean: java中的bean
// 反射运用
extern "C"
JNIEXPORT void JNICALL
Java_lanya_denganzhi_com_ndk_MainActivity_passObject(JNIEnv *env, jobject instance, jobject bean,
                                                     jstring string_) {
    const char *string = env->GetStringUTFChars(string_, 0);
    // C 中通过放射 来获取Java的属性、调用Java的方法
    // 反射调用 Java方法
    jclass beanCls= env->GetObjectClass(bean);
    // 签名格式: (参数签名)返回值签名
    // 获取method
    jmethodID  gidI= env->GetMethodID(beanCls,"getI","()I");
    jmethodID  setI= env->GetMethodID(beanCls,"setI","(I)V");
    // bean.setI(2000)  这里相当于
    env->CallVoidMethod(bean,setI,2000);
    // 调用方法, 返回值是int的call. Int表示方法返回值
    // 这里调用get方法
    jint result= env->CallIntMethod(bean,gidI);
     LOGE("bean---%d",result);
    // 调用static方法,类的
    //   public static void printInfo(String msg)
    jmethodID printInfo= env->GetStaticMethodID(beanCls,"printInfo","(Ljava/lang/String;)V");
    jstring jstr2= env->NewStringUTF("show printfl");
    env->CallStaticVoidMethod(beanCls,printInfo,jstr2);
    // 反射获取属性
    //  private int i;
    // int i= 1000;
    jfieldID jfieldID1 =env->GetFieldID(beanCls,"i","I");
    env->SetIntField(bean,jfieldID1,1000000);
    jint jint1=  env->GetIntField(bean,jfieldID1);
    LOGE("放射获取属性---%d",jint1);
    // 反射构建对象
    jclass bean2Class=env->FindClass("lanya/denganzhi/com/ndk/Bean2");
    // 获取构造方法 , 默认构造方法的 名称和 签名
    jmethodID construct =env->GetMethodID(bean2Class,"","(I)V");
    // 构造方法newInstance
    // bean2 是 c++中的引用  new Bean2(9999)
    jobject  bean2= env->NewObject(bean2Class,construct,9999);
    jfieldID jfieldID2Bean2= env->GetFieldID(bean2Class,"i","I");
    jint jint3=  env->GetIntField(bean2,jfieldID2Bean2);
    // 获取i属性
    LOGE("构造出来的bean2是---%d",jint3);
    env->DeleteLocalRef(jstr2);
    env->DeleteLocalRef(bean2Class);
    env->DeleteLocalRef(bean2);
    env->ReleaseStringUTFChars(string_, string);
}

5. 全局引用(强引用)  与 弱引用

强应用,可以跨栈使用
弱引用和强引用比较,使用的时候可能会被系统回收弱引用

       public void testArr(View view){
        invokeStronRef1();
    }
  
    public native void invokeStronRef1();

jclass beanStrongClass=NULL;
extern "C"
JNIEXPORT void JNICALL
Java_lanya_denganzhi_com_ndk_MainActivity_invokeStronRef1(JNIEnv *env, jobject instance) {
    // TODO
    // 反射构建对象
    jclass bean2Class=env->FindClass("lanya/denganzhi/com/ndk/Bean2");
    // 把它变成全局引用,强引用
   // beanStrongClass = (jclass) env->NewGlobalRef(bean2Class);
    // 弱全局引用
    beanStrongClass = (jclass) env->NewWeakGlobalRef(bean2Class);
    // 获取构造方法 , 默认构造方法的 名称和 签名
    jmethodID construct =env->GetMethodID(beanStrongClass,"","(I)V");
    // 构造方法newInstance
    // bean2 是 c++中的引用
    jobject  bean2= env->NewObject(beanStrongClass,construct,9999);
    jfieldID jfieldID2Bean2= env->GetFieldID(beanStrongClass,"i","I");
    jint jint3=  env->GetIntField(bean2,jfieldID2Bean2);
    LOGE("invokeStronRef1---%d",jint3);
}

上面方法执行以后,beanStrongClass 没有被释放,第二次调用


    public void  testArr2(View view){
        invokeStronRef2();
    }
	 public native void invokeStronRef2();

extern "C"
JNIEXPORT void JNICALL
Java_lanya_denganzhi_com_ndk_MainActivity_invokeStronRef2(JNIEnv *env, jobject instance) {
    // 对应一个弱引用,可能会被内存回收
     // 如何判断是否被内存回收
    // true,表示被释放了
    jboolean  isEqual= env->IsSameObject(beanStrongClass,NULL);
    if(isEqual){
        LOGE("true");
    }else{
        LOGE("false");
    }
    // 没有被释放
    if(beanStrongClass!=NULL && !isEqual){
        jmethodID construct =env->GetMethodID(beanStrongClass,"","(I)V");
        // 构造方法newInstance
        // bean2 是 c++中的引用
        // new Bean2()
        jobject  bean2= env->NewObject(beanStrongClass,construct,9999);
        jfieldID jfieldID2Bean2= env->GetFieldID(beanStrongClass,"i","I");
        // 获取i 属性
        jint jint3=  env->GetIntField(bean2,jfieldID2Bean2);
        // 不使用了,释放全局应用
        // env->DeleteGlobalRef(beanStrongClass);
        env->DeleteWeakGlobalRef(beanStrongClass);
        // 必须置空,否则悬空指针,内存被释放了,但是指针还在
        beanStrongClass=NULL;
        LOGE("invokeStronRef2---%d",jint3);
    }else{
        // 释放了
        LOGE("invokeStronRef2---%s", "已经被释放了");
    }
    // 获取构造方法 , 默认构造方法的 名称和 签名
}

7.  动态注册:

JNI_OnLoad  Java方法和 C方法注册绑定, 上面的1-6都是静态注册


 // 动态注册
    public void staticRegester(View view){
        invokeStatic(988888);
    }
	  
    public native void invokeStatic(int a);



#if 0
typedef struct {
    char *name;          
    char *signature;    
    void *fnPtr;          
} JNINativeMethod;
#endif
  // 对应映射的C方法
void invokeStaticC(JNIEnv *env, jobject cls,jint i){
    LOGE("invokeStaticC:%d",i);
}
// 结构体数组
static const JNINativeMethod methods[] = {
        {"invokeStatic", "(I)V", (void *)invokeStaticC},
};
JavaVM * _vm;
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
    _vm=jvm;
    LOGE("JNI_OnLoad---start");
    JNIEnv *env ;
    // jvm java虚拟机获取  JNIEnv
    // 0 成功
    if (jvm->GetEnv((void**)&env , JNI_VERSION_1_6) !=JNI_OK) {
        return JNI_ERR; 
    }
    jclass cls;
    cls = env->FindClass("lanya/denganzhi/com/ndk/MainActivity");
    if (cls == NULL) {
        return JNI_ERR;
    }
    
    
    jint methodCount= sizeof(methods)/sizeof(JNINativeMethod);
    LOGE("methodCount:%d",methodCount);
    if(env->RegisterNatives(cls,methods,methodCount)<0){
        return JNI_ERR;
    }
    LOGE("JNI_OnLoad---end");
    return JNI_VERSION_1_6;
}
 8. 切换线程

在新线程中获取  JNIEnv* 只能通过  JavaVM, 不能通过结构体传递


public  void switchThreadMethod(View view){
        switchThread();
    }
	   
    public native void switchThread();
	// C中 新线程调用Java中的  updateUI方法
	 public void updateUI(){
        if(Looper.myLooper()== Looper.getMainLooper()){
            Toast.makeText(MainActivity.this,"更新UI1",Toast.LENGTH_SHORT).show();
        }else{
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(MainActivity.this,"更新UI2",Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

struct Person{
    //jobject instance;
    // JNIEnv *env;
    int age;
};
void* threadTask(void* args){
    // env 切换线程,只能通过 _vm 构建 一个 env 环境
    // 不能通过 结构体 传递 Env对象
    JNIEnv* env;
    if(_vm->AttachCurrentThread(&env,0) != JNI_OK){
    };
    //Person* uperson =  static_cast(args);
      jobject instance = static_cast(args);
     // struct  Person* p= (struct Person*)(args);
      // LOGE("person.age...%d",p->age);
//    jobject instance = static_cast(p->instance);
    // 获取 MainActivity的 jclass对象
    jclass beanCls= env->GetObjectClass(instance);
    // 获取methodID
    jmethodID  updateUI= env->GetMethodID(beanCls,"updateUI","()V");
    env->CallVoidMethod(instance,updateUI);
//    delete(instance);
    env->DeleteGlobalRef(instance);
    //分离
    _vm->DetachCurrentThread();
    return 0;
}
extern "C"
JNIEXPORT void JNICALL
Java_lanya_denganzhi_com_ndk_MainActivity_switchThread(JNIEnv *env, jobject instance) {
//    Person* person=new Person;
//    person->env= env;
//    person->instance = env->NewGlobalRef(instance);  // instance  就是MainActivity的jobject
    // jinstance2  不能通过结构体成员传递,无效
    jobject jinstance2 = env->NewGlobalRef(instance);
    struct Person  p= { 67 };
    pthread_t  pid;
  // 启动线程,  env 如何跨线程传递
    pthread_create(&pid,0,threadTask,(void*)jinstance2);
}

归纳:
****  JNI 局域引用:
使用NewObject/FindClass/NewStringUTF  属于局部应用,出了方法,jvm回收无效
1. 方法执行完毕vm自动释放
2. 使用  NewStringUTF->ReleaseStringUTFChars
FindClass/NewStringUTF->DeleteLocalRef
上面的不释放也可以,在栈中
***  JNI 全局应用:可以跨方法/线程
*** 弱全局引用
 强应用,可以跨栈使用
 和强引用比较,使用的时候可能会被系统回收弱引用
必须要手动释放

作者:小置同学


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

基于Android Studio NDK开发

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

基于Android Studio NDK开发

1.  开发环境配置 Android Studio3.0.1 android-ndk-r13 gradle插件: classpath 'com.android.tools.build:gradle:3.0.1' gradle:distrib
2022-06-06

Android NDK开发入门

神秘的Android NDK开发往往众多程序员感到兴奋,但又不知它为何物,由于近期开发应用时,为了是开发的.apk文件不被他人解读(反编译),查阅了很多资料,其中有提到使用NDK开发,怀着好奇的心理,通过在线视频教育网站,我初步了解了NDK
2022-06-06

详解Android studio ndk配置cmake开发native C

Android 2.2 以后的版本对NDK的支持已经非常好了。最近把一个纯C的android项目,从eclipse ADT迁移到Android studio上。本文是参考Add C and C++ Code to Your Project
2023-05-30

Android NDK 开发教程

Android NDK 是在SDK前面又加上了“原生”二字,即Native Development Kit,因此又被Google称为“NDK”。众所周知,Android程序运行在Dalvik虚拟机中,NDK允许用户使用类似C / C++之类
2022-06-06

Android NDK开发详细介绍

Android之NDK开发 一、NDK产生的背景Android平台从诞生起,就已经支持C、C++开发。众所周知,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第三方应用都必须使用Java语言。但这并不
2022-06-06

Android Studio微信界面基础开发

Android Studio微信界面基础开发 基础页面开发 新建页面并编写#第一个框架处理,分为top,content,bottom事件处理函数MainActivity.java package com.example.wexin; imp
2022-06-06

Android NDK开发简单程序分享(Hello Word!)

在之前的博客中已经为大家介绍了,如何在win环境下配置DNK程序,本篇我将带大家实现一个简单的Hello jni程序,让大家真正感受一下NDK开发的魅力。这里我们选择使用C+JAVA开发Android程序,首先你必须了解C语言、JAVA语言
2022-06-06

Android 在现有项目中使用NDK开发

新建项目直接选中Native C++即可,本篇文章主要描述如何在现有项目中添加Native方法 添加步骤 1.AS中依次点击Preferences->Android SDK -> SDK Tools安装Cmake和NDK,如果安装过程中下载
2022-06-06

基于visual studio code + react 开发环境搭建步骤

本篇内容主要讲解“基于visual studio code + react 开发环境搭建步骤”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“基于visual studio code + react
2023-06-20

Android studio | Android APP开发快捷键

/********************************************************** 博主信息: 博主github:https://github.com/MichaelBeechan 博主CSDN:http
2022-06-06

Android NDK开发之:配置环境的详解

一、Windows:Windows下的开发环境需要安装以下软件:Java JDK Apache ANT Build SystemAndroid SDKCygwinAndroid NDKEclipse IDE1、安装Java JDKhttp:
2022-06-06

基于visual studio code+react开发环境搭建的方法

这篇“基于visual studio code+react开发环境搭建的方法”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“基
2023-06-05

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录