03_Android NDK中C语言调用Java代码,javah的使用,javap的使用以及生成签名,Android.mk的编写,C代码的编写

简介: 1  案例场景,通过C语言回调Java的代码,案例的最终界面:2  案例的代码结构如下:3 编写DataProvider的代码: package com.example.ndkcallback;   public class DataProvider {     //C调用java空方法     public void helloFromJav


1  案例场景,通过C语言回调Java的代码,案例的最终界面:

2  案例的代码结构如下:

3 编写DataProvider的代码:

package com.example.ndkcallback;

 

public class DataProvider {

    //C调用java空方法

    public void helloFromJava(){

       System.out.println("哈哈哈  我被调用了");

    }

    //C调用java中的带两个int参数的方法

    public int Add(int x,int y){

       int result=x+y;

       System.out.println("result:"+result);

       return result;

    }

    //C调用java中参数为string的方法

    public void printString(String s) {

       System.out.println(s);

    }

   

    public static void demo(){

       System.out.println("哈哈哈,我是静态方法");

    }

   

    public native void callMethod1();

    public native void callMethod2();

    public native void callMethod3();

    public native void callMethod4();

    public native void callMethod5();

}

4 通过DataProvider获得头文件

接着带有header的结构如下:

5 编写MainActivity代码:

package com.example.ndkcallback;

 

import android.os.Bundle;

import android.support.v7.app.ActionBarActivity;

import android.view.View;

 

public class MainActivity extends ActionBarActivity {

 

         DataProvider dp;

        

         static {

                   System.loadLibrary("hello");

         }

        

         public void helloFromJava() {

                   System.out.print("哈哈哈,我被调用了");

         }

        

         @Override

         protected void onCreate(Bundle savedInstanceState) {

                   super.onCreate(savedInstanceState);

                   setContentView(R.layout.activity_main);

                   dp = new DataProvider();

         }

        

         public void click1(View view){

                   dp.callMethod1();   

         }

        

         public void click2(View view){

                   dp.callMethod2();

         }

        

         public void click3(View view){

                   dp.callMethod3();

         }

        

         public void click4(View view){

                   dp.callMethod4();

         }

        

         public void click5(View view){

                   dp.callMethod5();

         }

}

6 编写布局文件activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context=".MainActivity" >

 

    <Button

        android:onClick="click1"

        android:id="@+id/button1"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_alignParentTop="true"

        android:text="回调javahelloFromJava" />

 

    <Button

         android:onClick="click2"

        android:id="@+id/button2"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@+id/button1"

        android:text="回调javaAdd" />

 

    <Button

        android:onClick="click3"

        android:id="@+id/button3"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@+id/button2"

        android:text="回调javaPrintString" />

 

    <Button

         android:onClick="click4"

        android:id="@+id/button4"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@+id/button3"

        android:text="回调java中其它类的方法" />

 

    <Button

        android:onClick="click5"

        android:id="@+id/button5"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@+id/button4"

        android:text="回调java中静态的方法" />

 

</RelativeLayout>

7 接下来,通过javap命令获得DataProvider的方法签名,在cygwin上进入/NdkCallBack/bin/classes.

命令如下:

toto@toto-PC /cygdrive/e/workspace/Android/NdkCallBack/bin/classes

$ javap -scom.example.ndkcallback.DataProvider

上面红框圈的分别是执行命令和方法签名。这个签名在hello.c中会用到。

7 接下来编写hello.c

#include "com_example_ndkcallback_DataProvider.h"

 

/**

 * 调用:DataProvider中的 public void helloFromJava();

 */

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod1

  (JNIEnv *env, jobject jobject) {

    /**

     * Class<?> forName = Class.forName("com.example.ndkcallback.DataProvider");

     * Method declaredMethod = forName.getDeclaredMethod("helloFromJava", new Class[]{});

     * declaredMethod.invoke(forName.newInstance(), new Object[]{});

     */

         //jclass      (*FindClass)(JNIEnv*, const char*);

    jclass clazz = (*env)->FindClass(env,"com/example/ndkcallback/DataProvider");

    //jmethodID (*GetMethodID)(JNIEnv*,jclass,const char*,const char*)

    //方法签名   参数和返回值

    //GetMethodID中参数分别是env指针,class,方法名,方法签名

    jmethodID methodId=(*env)->GetMethodID(env,clazz,"helloFromJava","()V");

    //通过 void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);来调用Java的代码

    (*env)->CallVoidMethod(env,jobject,methodId);

}

 

/**

 * 调用:DataProvider中的 public int Add(int, int);

 */

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod2

  (JNIEnv *env, jobject jobject) {

         jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/DataProvider");

         //这里的方法签名中有几个I表示有几个参数

         jmethodID methodId=(*env)->GetMethodID(env,clazz,"Add","(II)I");

         // jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);

         (*env)->CallIntMethod(env,jobject,methodId,3,5);

}

 

/**

 * 调用:DataProvider中的 public void printString(java.lang.String);

 */

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod3

  (JNIEnv *env, jobject jobject) { // 参数 object  就是native方法所在的类

         jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/DataProvider");

         jmethodID methodId=(*env)->GetMethodID(env,clazz,"printString","(Ljava/lang/String;)V");

         // jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);

         jstring str=(*env)->NewStringUTF(env,"hello");

 

         (*env)->CallVoidMethod(env,jobject,methodId,str);

}

 

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod4

  (JNIEnv * env, jobject j){

         jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/MainActivity");

         //  jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);

         // 方法签名  参数和返回值

         jmethodID methodId=(*env)->GetMethodID(env,clazz,"helloFromJava","()V");

         // void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);

         // 需要创建DataProvider 对象

         // jobject     (*AllocObject)(JNIEnv*, jclass);

         jobject obj=(*env)->AllocObject(env,clazz);  // new MainActivity();

         (*env)->CallVoidMethod(env,obj,methodId);

 

}

 

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod5

  (JNIEnv * env, jobject j){

         jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/DataProvider");

         //     jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);

          jmethodID  methodid=(*env)->GetStaticMethodID(env,clazz,"demo","()V");

         //void        (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);

          (*env)->CallStaticVoidMethod(env,clazz,methodid);

}

8 编写Android.mk文件,内容如下:

LOCAL_PATH := $(call my-dir)

 

include $(CLEAR_VARS)

 

LOCAL_MODULE    := libhello

LOCAL_SRC_FILES := Hello.c

 

include $(BUILD_SHARED_LIBRARY)

9 编写Android的清单文件,内容如下:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.example.ndkcallback"

    android:versionCode="1"

    android:versionName="1.0" >

 

    <uses-sdk

        android:minSdkVersion="8"

        android:targetSdkVersion="19" />

 

    <application

        android:allowBackup="true"

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme" >

        <activity

            android:name="com.example.ndkcallback.MainActivity"

            android:label="@string/app_name" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

 

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>

 

</manifest>

10 交叉编译,生成.so文件

成功之后,查看Android控制台打印的结果

 

 

目录
相关文章
|
14天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
37 3
|
21天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
57 2
|
1月前
|
存储 算法 程序员
C 语言递归算法:以简洁代码驾驭复杂逻辑
C语言递归算法简介:通过简洁的代码实现复杂的逻辑处理,递归函数自我调用解决分层问题,高效而优雅。适用于树形结构遍历、数学计算等领域。
|
1月前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
82 5
|
1月前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
57 5
|
2月前
|
Java API 开发者
Java中的Lambda表达式:简洁代码的利器####
本文探讨了Java中Lambda表达式的概念、用途及其在简化代码和提高开发效率方面的显著作用。通过具体实例,展示了Lambda表达式如何在Java 8及更高版本中替代传统的匿名内部类,使代码更加简洁易读。文章还简要介绍了Lambda表达式的语法和常见用法,帮助开发者更好地理解和应用这一强大的工具。 ####
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
65 1
|
1月前
|
安全 Java API
Java中的Lambda表达式:简化代码的现代魔法
在Java 8的发布中,Lambda表达式的引入无疑是一场编程范式的革命。它不仅让代码变得更加简洁,还使得函数式编程在Java中成为可能。本文将深入探讨Lambda表达式如何改变我们编写和维护Java代码的方式,以及它是如何提升我们编码效率的。
|
8月前
|
Java
使用Java代码打印log日志
使用Java代码打印log日志
330 1
|
Java BI API
在Java代码中打日志需要注意什么?
日志是什么?日志是你在代码运行时打印出来的一些数据和记录,是快速排查问题的好帮手,是撕逼和甩锅的利器!
717 0