Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

NDK探究之旅《十一》—C代码调用Java代码之项目实战

$
0
0

C代码调用Java代码步骤及其注意事项

今天我们来探究一下C语言是如何调用Java代码的

我们先来看一下Java代码是如何调用C代码的

Markdown

那C代码是如何调用Java代码的呢?

Markdown

C调用Java中的方法

其实就是从java中调用c,从C中调用java的方法,可以看做是一个回调

Java中没有参数的方法

1.在java中写一个本地方法

public native void methodInC();

2.使用命令提示符进入到项目下的bin/classes目录下,使用javah 类的全路径 命令得到本地方法的头文件

3.在项目上点右键–>Android Tools–>Add Native Support,给我们的C代码起一个名字,点确定,会自动生成一个jni的目录和c代码(一般生成的是.cpp,把后缀改为.c)

4.自动生成的Android.mk文件中的编译源文件是.cpp,改为c(如果第三步没有改,则不需要改)

#指定编译的文件夹  指定当前文件目录
LOCAL_PATH := $(call my-dir)
#编译器会定义很多的临时变量,中间变量,最好清空所有的中间变量。
include $(CLEAR_VARS)
#编译出来模块的名称(编译后的名字,也就是存放于libs目录下的名字,不带扩展名)
LOCAL_MODULE    := hello
# 编译的源代码的名称(要编译的c代码的名称,带扩展名)
LOCAL_SRC_FILES := hello.c      
#编译一个动态库
include $(BUILD_SHARED_LIBRARY)

5.如果需要在除arm处理器的其它机型上使用,需要在jni目录下创建一个Application.mk文件(如果只是在arm下使用,可以跳过此步骤),需要哪一个处理器,就配置哪一个,不要配置太多,因为生成的文件会很大

APP_ABI := arm x86 mips

6.把ndk安装的目录下的android-ndk-r9b\platforms\android-16\arch-arm\usr\include/jni.h复制到项目的jni目录下(平台就现在版本没有任何区别,哪一个版本下的都可以)
7.写C代码

#include <jni.h>
#include "stdio.h"
#include "com_itheima_calljava_DataProvider.h"


/**
 * 用C代码调用java代码中的方法,去发送一条短信
 */
JNIEXPORT void JNICALL Java_com_demo_calljava_DataProvider_methodInC
  (JNIEnv* env, jobject obj){
    //第一步:找到要调用的方法的class字节码文件
        jclass clazz = (*env)->FindClass(env,"com/itheima/calljava/DataProvider");
    //第二步:找到这个类中的方法.参数依次为:JVM虚拟机环境、class对象、方法名、方法签名(返回值+方法的形参)
        jmethodID mid = (*env)->GetMethodID(env,clazz,"methodInjava","()V");
    //第三步:调用这个方法
        (*env)->CallVoidMethod(env,obj,mid);
}

8.在要调用本地方法的类中使用静态代码块的方式加载生成的c代码库

static{
    //这个名字是在Android.mk中的LOCAL_MODULE的值,不带前缀,不带扩展名
    System.loadLibrary("hello");
}

9.只要在java中调用本地方法methodInC即可
注: Java中的被C调用的方法

/**
 * 让C调用此方法,发送一条短信
 */
public void methodInjava(){
    Log.i(TAG,"-------------------------");
    //创建短信管理对象 
    SmsManager smsManager = SmsManager.getDefault();
    //发送一条文本短信
    smsManager.sendTextMessage("5556", null, "hello 5556", null, null);
}

如何去获取方法的签名

Javap -s com.包名.类名

如:

Markdown

Markdown

Demo相关示例:

C语言调用Java中的方法去Toast吐司和Log日志打印

Markdown

相关代码:

public class ServiceProvider {

    public  void methodInJavaSource(){
        System.out.print("-------->我来了");
        LogUtil.e("yuyahao","-------->我来了");
        for (int i = 0; i < 20; i++) {
            GetToast.useString(MyApplication.getInstance(),"C代码来调用我啦啦啦..."+i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 调用C代码,让C代码再次调用Java代码
     */
    public native void callFromCMethod();
}

MainActivity

public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("serviceData");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        try {
           Class service =  getClassLoader().loadClass("jni.yyh.com.mycptojavanative.jni.ServiceProvider");
            Method method = service.getMethod("methodInJavaSource",new Class []{});
            method.invoke(service.newInstance(),new  Object[]{});
            //调用其方法

        } catch (Exception e) {
            e.printStackTrace();
        }

        findViewById(R.id.btn_onclick).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ServiceProvider serviceProvider = new ServiceProvider();
                serviceProvider.callFromCMethod();
            }
        });
    }
}

主要的就是C代码:

#include <stdio.h>
#include"jni_yyh_com_mycptojavanative_jni_ServiceProvider.h"
#include <android/log.h>
#include"jni.h"
#define LOG_TAG "System.out.c"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

//java中调用c代码,直接调用native方法即可。
JNIEXPORT void  Java_jni_yyh_com_mycptojavanative_jni_ServiceProvider_callFromCMethod(JNIEnv * env, jobject obj){
    char * pageName = "jni/yyh/com/mycptojavanative/jni/ServiceProvider";
  //第一步,首先找到Java 中的class对象
  jclass clzz = (*env)->FindClass(env,pageName);
  //第二步,找到class里面的一个方法
  jmethodID methodid = (*env)->GetMethodID(env,clzz,"methodInJavaSource","()V");
    int ss = 0;
    LOGD("pagename=%d");
    LOGI("pagename=%s",pageName);
  //第三步调用clas里面的一个方法
  (*env)->CallVoidMethod(env,obj,methodid);

}

相关Demo下载地址:

C语言调用Java方法进行Toast吐司和Log日志进行打印

https://github.com/androidstarjack/MyCpToJavaNative

博客地址:

http://blog.csdn.net/androidstarjack/article/details/72758094

NDK探究之旅:

NDK探究之旅《一》——对jni和NDK的认识

NDK探究之旅《二》——C语言的基本认识

NDK探究之旅《三》—C语言的输入输出函数

NDK探究之旅《四》——指针的强化理解

NDK探究之旅《五》——指针和数组之间的关系

NDK探究之旅《六》—函数的指针、结构体、枚举、宏定义

NDK探究之旅《七》—函数指针,宏定义的优缺点及应用场景

NDK探究之旅《八》——jni的开发流程规范及环境配置

NDK探究之旅《九》——jni开发中常见的错误及其注意事项

NDK探究之旅《十》——ndk项目实战之Androidstudio开发经验总结

### 相信自己,没有做不到的,只有想不到的
如果你觉得此文对您有所帮助,欢迎入群 QQ交流群 :232203809
微信公众号:终端研发部

Markdown

(欢迎关注学习和交流)

作者:androidstarjack 发表于2017/6/1 9:02:01 原文链接
阅读:60 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>