Activity


public class MainActivity extends ListActivity {
    static {
        System.loadLibrary("hello");// 在java代码中引入libs目录下的库函数,文件名为【libhello.so】。注意,引入时的文件名要去掉前面的lib和后面的.so        
        System.loadLibrary("hellocpp");
    }

    private TextView tv_info;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String[] array = { "调用C中的无参方法,返回一个字符串", //
                "调用C中的有参方法,返回处理1+2后的值",//
                "对字符串进行处理", //
                "对int数组进行处理",//
                "调用C++中的无参方法,返回一个字符串", };
        tv_info = new TextView(this);
        tv_info.setTextColor(Color.BLUE);
        tv_info.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
        tv_info.setPadding(20, 10, 20, 10);
        getListView().addFooterView(tv_info);
        setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<String>(Arrays.asList(array))));
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        switch (position) {
        case 0:
            String stringFromC = MyNativeMethods.getInstance().helloFromC();
            tv_info.setText(stringFromC);
            break;
        case 1:
            int intFromC = MyNativeMethods.getInstance().passwordFromC(1, 2);
            tv_info.setText(intFromC + "");
            break;
        case 2:
            tv_info.setText(MyNativeMethods.getInstance().encodeFromC("abc123", 1));
            break;
        case 3:
            int array[] = MyNativeMethods.getInstance().intMethod(new int[] { 1, 2, 3, });
            tv_info.setText(Arrays.toString(array));
            break;
        case 4:
            tv_info.setText(MyNativeMethods.getInstance().helloFromCPP());
            break;
        }
    }
}

本地方法

/** 存放native方法的类 */
public class MyNativeMethods {
    /**返回一个字符串*/
    public native String helloFromC();
    /**返回int类型计算后的结果*/
    public native int passwordFromC(int x, int y);
    /**对给定字符串进行处理,模拟加密运算*/
    public native String encodeFromC(String text, int length);
    /**给c代码传递int数组,让c代码给这个数组进行操作;模拟多媒体解码*/
    public native int[] intMethod(int[] iNum);
    /**c++中的方法*/
    public native String helloFromCPP();
    //******************************************************************************************
    private static MyNativeMethods mEmployee;
    private MyNativeMethods() {
    }
    public static MyNativeMethods getInstance() {
        if (mEmployee == null) {
            mEmployee = new MyNativeMethods();
        }
        return mEmployee;
    }
}

c文件

#include <stdio.h>
#include <stdlib.h>
#include <jni.h>//必须添加的头文件
#include <string.h>
#include "com_bqt_hellofromc_MyNativeMethods.h"//引入生成的头文件,注意要把此文件放在jni文件夹中,src目录下的此文件不需要了
//在C中使用log,除在此声明外,还需在Android.mk文件中增加【LOCAL_LDLIBS += -llog】
#include <android/log.h>//引入log头文件
#define LOG_TAG "bqt"// 这个是自定义的LOG的标识
//定义一些输出的LOG函数
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG ,__VA_ARGS__) // 定义LOGF类型
//******************************************************************************************【1】返回一个字符串
JNIEXPORT jstring JNICALL Java_com_bqt_hellofromc_MyNativeMethods_helloFromC(JNIEnv *env, jobject obj) {
    //写成【JNIEnv * env】或【JNIEnv *env】或【JNIEnv*env】都可以。【返回值】【方法名】【参数列表】返回值类型jstring就是java中的string
    char* cstr = "hello from c"; //  char*  在c中可用来表示一个字符串。注意,这里绝对不能有中文
    jstring jstr = (*env)->NewStringUTF(env, cstr);
    return jstr;
}
//******************************************************************************************【2】返回int类型计算后的结果
JNIEXPORT jint JNICALL Java_com_bqt_hellofromc_MyNativeMethods_passwordFromC(JNIEnv * env, jobject obj, jint a, jint b) {
    return a + b + 10000; //c中的int占用字节数在不同环境下可能不同,可能是0-65535,所以,稍微大一点的数(十万级别)都得用double
}
//******************************************************************************************【3】对给定字符串进行处理,模拟加密运算
JNIEXPORT jstring JNICALL Java_com_bqt_hellofromc_MyNativeMethods_encodeFromC(JNIEnv * env, jobject obj, jstring passwd, jint length) {
    //char* cstr = Jstring2CStr2(env, passwd); //将java的字符串转化为c语言。卧槽这方法编译不通过,估计是因为找不到一些库之类的东西的原因!
    //    int i = 0;
    //    for (i = 0; i < length; i++) {
    //        *(cstr + i) += 1; //给C语言字符加1
    //    }
    char* cstr = "abc";
    return (*env)->NewStringUTF(env, cstr); //将c语言字符串转化为java字符串
}
//******************************************************************************************【4】对给定数组进行操作,模拟多媒体解码
JNIEXPORT jintArray JNICALL Java_com_bqt_hellofromc_MyNativeMethods_intMethod(JNIEnv * env, jobject jobject, jintArray arr) {
    int len = (*env)->GetArrayLength(env, arr); // 获取数组的长度
    LOGI("ArrayLength=%d", len);
    //LOG中也不能有中文
    jint* p = (*env)->GetIntArrayElements(env, arr, 0); //取出数组中第一个元素的内存地址
    //If isCopy is not NULL, then *isCopy is set to JNI_TRUE if a copy ismade; if no copy is made, it is set to JNI_FALSE.
    int i = 0;
    for (; i < len; i++) {
        LOGI("before-%d-=%d", i, *(p+i));
        //这一步没问题,会一个个打印所有数组中的内容
        *(p + i) += 5; //取出的每个元素加5
        LOGI("after-%d-=%d", i, *(p+i));
        //这一步也没问题,会一个个打印处理后的内容
    }
    jint* elems = (*env)->GetIntArrayElements(env, arr, 0); //再次获取元素的内存地址
    LOGI("ok-%d-=%d", i, *elems);
    //但返回的为啥还是未经处理的?
    //重新创建一个数组
    jintArray array = (*env)->NewIntArray(env, len); //Construct构造 a new primitive array object基本数组对象
    int ii = 0;
    int jj;
    for (; ii < len; ii++) {
        jj = 10000 + ii;
        (*env)->SetIntArrayRegion(env, array, ii, 1, &jj); //Sets the value of one element in a primitive array.其中【&】代表【取地址】操作,而非逻辑操作
        //(*env)->SetIntArrayRegion(env,array,【start】,【len】,buffer) , 从start开始复制长度为len 的数据 buffer到 array 中
    }
    return array;
}
//******************************************************************************************【工具方法】把java的字符串转换成c的字符串
char* Jstring2CStr(JNIEnv* env, jstring jstr) {
    char* rtn = NULL;
    //1:先找到字节码文件
    jclass clsstring = (*env)->FindClass(env, "Java/lang/String"); //Java或java都一样
    jstring strencode = (*env)->NewStringUTF(env, "GB2312"); //和UTF-8不行
    //2:通过字节码文件找到方法ID
    jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");
    //3:通过方法id,调用方法
    jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte("GB2312");
    //4:得到数据的长度
    jsize alen = (*env)->GetArrayLength(env, barr);
    //5:得到数据的首地址
    jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
    //6:得到C语言的字符串
    if (alen > 0) {
        rtn = (char*) malloc(alen + 1); //"\0"
        memcpy(rtn, ba, alen);
        rtn[alen] = 0;
    }
    (*env)->ReleaseByteArrayElements(env, barr, ba, 0); //
    return rtn;
}

c++文件

#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
#include "com_bqt_hellofromc_MyNativeMethods.h"//引入生成的头文件,这个东西在这里又必须要了!
JNIEXPORT jstring JNICALL Java_com_bqt_hellofromc_MyNativeMethods_helloFromCPP(JNIEnv *env, jobject obj) {
    return env->NewStringUTF("hello c++");
}

Android.mk文件

LOCAL_PATH := $(call my-dir)
# C/C++代码所在目录,也就是我们的jni目录,不必修改
        
include $(CLEAR_VARS)
LOCAL_LDLIBS += -llog
#若要在C中使用log,①需在.c中添加一系列声明,②还需在Android.mk文件中增加【LOCAL_LDLIBS += -llog】
#必须把LOCAL_LDLIBS :=-llog放在【include $(CLEAR_VARS)】后面才有用

LOCAL_MODULE    := hello
# 对应打包成函数库的名字,编译器会自动在前面加上lib,在后面加上.so
LOCAL_SRC_FILES := hello.c
# 对应c代码的文件 hello.c  

#不知道能不能同时编译多个
#LOCAL_MODULE    := hellocpp
#LOCAL_SRC_FILES := hello.cpp

include $(BUILD_SHARED_LIBRARY)

Application.mk文件

APP_ABI := armeabi armeabi-v7a x86
#Application.mk文件的目的是,描述在你的应用程序中所需要的模块(即静态库或动态库)
#APP_ABI 的值以空格区分,代表要支持的架构,默认为【armeabi】。其他架构,ARMv7 【armeabi-v7a】;IA-32 【 x86】
#每增加一个架构,编译后都会在lib目录下生成一个相应的文件夹,文件夹下的文件都是同名的.so文件(当然文件内容不一样)

javah生成的.h头文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_bqt_hellofromc_MyNativeMethods */
#ifndef _Included_com_bqt_hellofromc_MyNativeMethods
#define _Included_com_bqt_hellofromc_MyNativeMethods
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_bqt_hellofromc_MyNativeMethods
 * Method:    helloFromC
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_bqt_hellofromc_MyNativeMethods_helloFromC
  (JNIEnv *, jobject);
/*
 * Class:     com_bqt_hellofromc_MyNativeMethods
 * Method:    passwordFromC
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_bqt_hellofromc_MyNativeMethods_passwordFromC
  (JNIEnv *, jobject, jint, jint);
/*
 * Class:     com_bqt_hellofromc_MyNativeMethods
 * Method:    encodeFromC
 * Signature: (Ljava/lang/String;I)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_bqt_hellofromc_MyNativeMethods_encodeFromC
  (JNIEnv *, jobject, jstring, jint);
/*
 * Class:     com_bqt_hellofromc_MyNativeMethods
 * Method:    intMethod
 * Signature: ([I)[I
 */
JNIEXPORT jintArray JNICALL Java_com_bqt_hellofromc_MyNativeMethods_intMethod
  (JNIEnv *, jobject, jintArray);
/*
 * Class:     com_bqt_hellofromc_MyNativeMethods
 * Method:    helloFromCPP
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_bqt_hellofromc_MyNativeMethods_helloFromCPP
  (JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif

附件列表

JNI Java调用C代码 示例的更多相关文章

  1. 通过JNI实现java调用C代码和C代码调用java的代码

    一.java调用C代码 1)java中需要声明调用的函数,也就是native方法,并通过System.LoadLibrary来调用dll或者so(C代码).实例代码如下: public class H ...

  2. windows和linux环境下java调用C++代码-JNI技术

    最近部门做安卓移动开发的需要调C++的代码,困难重重,最后任务交给了我,查找相关资料,没有一个教程能把不同环境(windows,linux)下怎么调用说明白的,自己在实现的过程中踩了几个坑,在这里总结 ...

  3. java调用python代码

    同样的我们需要安装jython,具体的步骤如下: 1. 去 http://sourceforge.net/projects/jython/ 下载最新的jython相关的jar包. 2. 下载下来的ja ...

  4. cocos2d 中使用jni Java 调用 C++ 方法

    1.首先是LoadLibrary cocos2d中的C++代码会编译成一个.so文件.放在安卓文件夹下的libs/armeabi 下,然后java会load进来,这步我们不用做了,由于cocos2d已 ...

  5. C++用LuaIntf调用Lua代码示例

    C++用LuaIntf调用Lua代码示例 (金庆的专栏 2016.12) void LuaTest::OnResponse(uint32_t uLuaRpcId, const std::string& ...

  6. 01_JNI是什么,为什么使用,怎么用JNI,Cygwin环境变量配置,NDK案例(使用Java调用C代码),javah命令使用

    1 什么是JNI JNI Java本地开发接口 JNI是一个协议,这个协议用来沟通java代码和外部的本地代码(C/C++) 通过这个协议,java代码就可以调用外部的C/C++代码,外部的C/C++ ...

  7. [JNI] Java 调用 C++ dll

    首先介绍一下JNI吧! JNI 是Java提供的一个用于调用本地接口的接口层,位于Java代码 和 本地代码之间的一层:主要功能是 数据类型的转换,还有就是通过这一层来调用本地代码! 下面就说说Jav ...

  8. 天气类API调用的代码示例合集:全国天气预报、实时空气质量数据查询、PM2.5空气质量指数等

    以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 全国天气预报:数据来自国家气象局,可根据地名.经纬度GPS.IP查 ...

  9. 位置信息类API调用的代码示例合集:中国省市区查询、经纬度地址转换、POI检索等

    以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 中国省市区查询:2017最新中国省市区地址 经纬度地址转换:经纬度 ...

随机推荐

  1. Hadoop-CDH5.7.0 for CentOS7

    一.需求 系统 CentOS 7 最小化安装 JDK环境 JDK版本:1.8.0_91 jdk-8u91-linux-x64.rpm 下载地址:http://www.oracle.com/techne ...

  2. MLlib 编程指导-spark-1.2.0

    本文来自 http://spark.apache.org/docs/latest/mllib-guide.html 官方文档翻译 个人翻译 MLlib包括的算法和工具主要有:分类,回归,聚类,协同过滤 ...

  3. Lucene查询条数限制

    运用Lucene进行索引,在查询的时候是有条数限制的 public virtual TopFieldDocs Search(Query query, Filter filter, int n, Sor ...

  4. Hash查找法在Keil C51中的实现

    摘要:散列(hash)是一种重要的存储方法,也是一种常见的查找方法.它是指在记录的存储位置和它的关键字之间建立一个确定的对应关系.本文以射频卡门禁控制器为例,说明用射频卡卡号作为关键字,用Hash查找 ...

  5. "Failed to fetch URL https://dl-ssl.google.com/android/repository/addons_list.xml,reason: Connection

    "Failed to fetch URL https://dl-ssl.google.com/android/repository/addons_list.xml,reason: Conne ...

  6. sql union代替or

    ---原始SQL SQL> SELECT deptno FROM emp WHERE empno = 7788 OR job = 'SALESMAN' ORDER BY 1; DEPTNO -- ...

  7. 【HDOJ】1158 Employment Planning

    简单DP. #include <cstdio> #include <cstring> #include <cstdlib> #include <climits ...

  8. COCI2014-2015CONTEST#7——POLICE

    http://www.hsin.hr/coci/archive/2014_2015/contest7_tasks.pdf [题目描述] 有N个书架,每个书架可以容纳M本书.给出了若干本书,每本书有一个 ...

  9. 矢量做图组件OTGisX的使用(类似Mapbase)

    一:组件添加到工具栏 要在应用程序中应用OTGisX控件,首先要把所下载的OTGisX组件添加到.Net工程中.并将其添加到工具箱托盘中.添加方式为:在工具箱上单击右键,选择“选择项”,会出现“选择工 ...

  10. 在Visual Studio中使用AStyle

    最近在做一个C++项目,我们使用了一个叫做AStyle的插件来做代码格式化. 下载方式1:通过Visual Studio下载 启动Visual Studio,以下简称VS: 英文版VS:VS主菜单 & ...