JNI(Java Native Interface)_03

JNI(Java Native Interface)_03

c/c++区别

jni调用:

*   c: jstring str = (*env)->NewStringUTF(env,getHello());
*  c++:jstring str = (env)->NewStringUTF(getHello());
*  区别如下:
*  1,c++中把(*env) 的\*号去掉
*  2,调用函数的时候吧参数env去掉
*  3,c中是结构体  c++是类
*  4,c结构体中的函数指针  c++类的成员函数(c结构体不能声明函数)
*  5,c 申请内存用malloc /realloc ,c++ 申请空间用new
*  6,c 释放内存用free()  ,c++ 释放空间用 delete
*  7, c++ 结构体和class基本一致(除了访问权限,结构体的访问权限没有类多)

1种开发模式

* 1, java程序员定义好native
* 2, java程序员生成jni规范
* 3, 找一个c程序员写好代码实现
* 4, 通过jni调用(.so)

2种开发模式

* 1,c代码已经写好
* 2,根据c代码定义native方法
* 3,jni规范
* 4,调用(.so)

3种开发模式

* 1. .so文件已经生成
* 2, 拿到jni规范
* 3, 直接调用

jni实际开发

案例一:10_锅炉监控1

锅炉监控的由来:

北方天气很冷,所以需要锅炉加热来取暖,但是锅炉加热如果不监控的话,会产生温度过高而导致爆炸,而人为的监控比较麻烦,所以我们就可以给锅炉加上一个电子监控器(C语言控制的),而当监控器监控到温度过高,就可以给通过与Java语言通信而给用户发送信息告知,如果C与java不通信的话,单靠C语言实现给设备发送信息,这实现难度难以估计。这就是这个案例的由来

案例目的:

1、演示在jni文件夹下的c程序如何调用别的c程序的方法
2、为完成锅炉监控的全功能实现做铺垫

案例步骤:

1,创建工程

右键工程-->android tools-->add native support->输入动态库名字->点击确定

2,把cpp改为c,同时在Android.mk文件中也把cpp改成c

3,定义java中native方法

/**
 * 该方法获取锅炉发来的监控数据,这里为了模拟就采用C语言调用伪随机数发来的数据
 * @return
 */
public native int getPress();

4,实现c代码

这一步和之前的不一样了,这里需要在jni自动生成的c文件里调用另外一个c文件里的方法,这样可以降低耦合性。可以另程序员工作量大大减低

guolu.c
#include <stdio.h>
#include<stdlib.h>

/*

*/
int getNumber()
{
    return rand() % 100;//锅炉压力表
}

main()
{
      printf("%d\n",getNumber());
      system("pause");
}

5,在c源文件中实现jni规范(native方法) javah命令参考上面

    右键工程--》properties->c/c++ general->paths and symbols 选择includes 点击add 把I:\android-ndk-r9\platforms\android-9\arch-arm\usr\include 保存

6,在c源文件中实现jni方法

guolu1.c

#include <jni.h>

jint Java_com_itheima_guolu1test_MainActivity_getPress
  (JNIEnv * env, jobject obj)
{
    return getNumber();//可以直接调用了
}

7,java中加载.so文件

package com.itheima.guolu1test;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {
    static{
        System.loadLibrary("guolu1");
    }
    /**
     * 该方法获取锅炉发来的监控数据,这里为了模拟就采用C语言调用伪随机数发来的数据
     * @return
     */
    public native int getPress();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void click(View view){
        Toast.makeText(this, getPress()+"", 0).show();

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

8,运行

案例二、11_锅炉监控2

案例目的:

1、加强案例一的功能:用seekbar控件来展示

2、演示C程序和Java程序间的方法互调

案例步骤

1、创建工程 右键工程-->android tools-->add native support->输入动态库名字->点击确定

2、把cpp改为c,同时在Android.mk文件中也把cpp改成c

3、定义java中native方法

public native void startMonitor();
public native void stopMonitor();

4、实现c代码

guolu.c

#include <stdio.h>
#include<stdlib.h>

/*

*/
int getNumber()
{
    return rand() % 100;//锅炉压力表
}

main()
{
      printf("%d\n",getNumber());
      system("pause");
}

guolu1.c

#include <jni.h>

jint Java_com_itheima_guolu1test_MainActivity_getPress
  (JNIEnv * env, jobject obj)
{
    return getNumber();//可以直接调用了
}

int state;
void  Java_com_itheima_guolu1test_MainActivity_startMonitor
  (JNIEnv *env, jobject obj)
{
    state = 1;
    while(state){
        int press = getNumber();
        //1,class
        //jclass      (*FindClass)(JNIEnv*, const char*);
        jclass clazz = (*env)->FindClass(env,"com/itheima/guolu1test/MainActivity");
        //2,method
        // jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
        jmethodID mid = (*env)->GetMethodID(env,clazz,"setMyProgress","(I)V");
        //3,obj
        //4,invoke
        //    void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
        (*env)->CallVoidMethod(env,obj,mid,press);
        sleep(1);
    }
}

void  Java_com_itheima_guolu1test_MainActivity_stopMonitor
  (JNIEnv *env, jobject obj)
{
    state = 0;

}

5、在c源文件中实现jni规范(native方法) javah命令参考上面

右键工程--》properties->c/c++ general->paths and symbols 选择includes 点击add 把I:\android-ndk-r9\platforms\android-9\arch-arm\usr\include 保存

6、在c源文件中实现jni方法

7、java中加载.so文件

<LinearLayout 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"
  android:orientation="vertical"
    tools:context=".MainActivity" >

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="开始监控"
        android:onClick="startclick" />
    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="停止监控"
        android:onClick="endclick" />
    <SeekBar
        android:id="@+id/seek"
                android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        />
</LinearLayout>

package com.itheima.guolu1test;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.SeekBar;
import android.widget.Toast;

public class MainActivity extends Activity {
    private SeekBar seek;
    static{
        System.loadLibrary("guolu1");
    }
    public native void startMonitor();
    public native void stopMonitor();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        seek = (SeekBar) findViewById(R.id.seek);
        seek.setMax(100);
    }
    public void setMyProgress(int progress){
        seek.setProgress(progress);
    }

    public void startclick(View view){
        new Thread(){
            public void run(){
                startMonitor();
            };
        }.start();
    }
    public void endclick(View view){
        new Thread(){
            public void run(){
                stopMonitor();
            };
        }.start();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

8、运行

案例三、12_自定义ViewTest

案例目的

1、可以不使用Android提供的控件去显示监控的数据,而使用自定义的控件

2、为后面的综合锅炉监控案例做铺垫

案例步骤

1、新建一个MyView继承View

2、实现View的所有构造函数

3、重写onDraw方法

代码如下:

package com.itheima.zidinyiView;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class MyView extends View {
    private int currentPress = 60;
    public MyView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyView(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint  = new Paint();
        paint.setStrokeWidth(2);
        paint.setTextSize(20);
        if(currentPress<50){
            paint.setColor(Color.GREEN);
        }else if(currentPress<70){
            paint.setColor(Color.YELLOW);
        }else if(currentPress<90){
            paint.setColor(Color.BLUE);
        }else {
            paint.setColor(Color.RED);
        }
        //float left, float top, float right, float bottom, Paint paint)
        canvas.drawRect(50, 300 - currentPress, 100, 300, paint);
        //画东西到左面上
        canvas.drawText("当前压力值:", 130, 270, paint);
    }

    public int getCurrentPress() {
        return currentPress;
    }

    public void setCurrentPress(int currentPress) {
        this.currentPress = currentPress;
    }

}

4、在layout里使用该自定义的控件(继承了View的自定义类)去布局

<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <com.itheima.zidinyiView.MyView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        />

</RelativeLayout>

5、在手机上测试布局是否满意

案例四、13_锅炉监控3

案例目的:

1、把之前的锅炉监控案例综合起来,加入自定义的显示控件,和自己的功能

案例步骤:工程内容大致和案例二一样

1、把案例三实现的MyView复制过来

2、改写工程的layout布局

<LinearLayout 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"
  android:orientation="vertical"
    tools:context=".MainActivity" >

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="开始监控"
        android:onClick="startclick" />
    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="停止监控"
        android:onClick="endclick" />
    <com.itheima.guolu1test.MyView
                android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/myView"
        />
</LinearLayout>

3、然后在MainActivity里实现该控件

package com.itheima.guolu1test;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.SeekBar;
import android.widget.Toast;

public class MainActivity extends Activity {
//  private SeekBar seek;
    private MyView view;
    static{
        System.loadLibrary("guolu1");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//        seek = (SeekBar) findViewById(R.id.seek);
//        seek.setMax(100);
        view = (MyView) findViewById(R.id.myView);
    }
    public void setMyProgress(int progress){
//      seek.setProgress(progress);
        if(progress>90){
            //发送短信
            //播放警告音乐
        }
        view.setCurrentPress(progress);
    }

    public native void startMonitor();
    public native void stopMonitor();

    public void startclick(View view){
        new Thread(){
            public void run(){
                startMonitor();
            };
        }.start();
    }
    public void endclick(View view){
        new Thread(){
            public void run(){
                stopMonitor();
            };
        }.start();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

案例结果:

案例四、14_卸载监听

案例目的:

1、演示android的app如果在里面有交叉调用了C程序的方法,而在C程序方法中如果使用到了分叉函数fork();,而导致的app被卸载后C程序产生的进程还继续在手机里运行不会停止。也就是所谓的流氓软件所使用到的手段

案例步骤:

1、创建工程 右键工程-->android tools-->add native support->输入动态库名字->点击确定

2、把cpp改为c,同时在Android.mk文件中也把cpp改成c

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_LDLIBS += -llog
LOCAL_MODULE    := removeListener
LOCAL_SRC_FILES := removeListener.c

include $(BUILD_SHARED_LIBRARY)

3、定义java中native方法

public native void shabusi();//杀不死的方法

4、实现c代码

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

void  Java_com_itheima_removelistenerTest_MainActivity_shabusi
(JNIEnv * env, jobject obj)
{
    //分叉函数
    //当java软件被卸载后还会继续发出这些信息,因为在c程序里的这个分叉函数java程序关不掉,所以程序员需要职业道德
    //使用c程序去监听文件包什么时候被删去了,如果删去了就关掉这个分叉函数产生的线程
    int res = fork();
    if(res == 0){
        while(1){//死循环
            LOGI("我还活着\n");
            sleep(1);
            LOGI("我还活着1");
        }
    }
}

5、在c源文件中实现jni规范(native方法) javah命令参考上面

右键工程--》properties->c/c++ general->paths and symbols 选择includes 点击add 把I:\android-ndk-r9\platforms\android-9\arch-arm\usr\include 保存

6、在c源文件中实现jni方法

7、java中加载.so文件

package com.itheima.removelistenerTest;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {
    static{
        System.loadLibrary("removeListener");
    }
    public native void shabusi();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        shabusi();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

8、运行

App卸载前

App卸载

App卸载后

案例五、15_cpphello

案例目的:

1、Java和C++如何交叉编程
2、在android中输出hello

案例步骤:

1、创建工程 右键工程-->android tools-->add native support->输入动态库名字->点击确定

2、定义java中native方法

public native String helloFromCpp();

3、在cpp源文件中实现jni规范(native方法),使用javah命令,而生成的java头文件也要导入到jni文件夹中,并在cpp文件里声明该头文件

4、实现cpp方法

#include <jni.h>
#include<com_itheima_cpphelloTest_MainActivity.h>

////public native String helloFromC() Java_包名_类名_方法名(JNIEnv* env,jobject obj)
//// doGet(reqeust,response)
//jstring Java_com_itheima_helloworld_MainActivity_helloFromC(JNIEnv* env,jobject obj)
//{
//  //jstring     (*NewStringUTF)(JNIEnv*, const char*);
//  jstring str = (*env)->NewStringUTF(env,getHello());
//  return str;
//}
//以上是c的jni调用过程
//和以上区别的是,c++的调用过程如下,是有区别的
 jstring  Java_com_itheima_cpphelloTest_MainActivity_helloFromCpp
  (JNIEnv *env, jobject obj){
     return (env)->NewStringUTF("hello from cpp");
 }

5、在MainActivity中调用方法

package com.itheima.cpphelloTest;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {
    static{
        System.loadLibrary("cpp");
    }
    public native String helloFromCpp();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toast.makeText(this, helloFromCpp(), 1).show();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

6、运行

时间: 2024-08-25 02:50:31

JNI(Java Native Interface)_03的相关文章

Android Jni(Java Native Interface)笔记

首先记录一个问题,关于如何用javah生成头文件的. 总是提示“无法访问android.app.Activity”,网上查了说是要指定android.jar的位置,可以在classpath里指定,也可以在命令中直接指定.在windows下两种都试了,都不行.于是装ubuntu.装ubuntu挺麻烦,一开始想用wubi在windows下安装,失败.后来用了某个启动器在硬盘安装.还有分配swap,根目录/,home目录的大小..真是难倒外行人.安装好了之后试了一下,好像还是不行.. 再百度.在csd

JNI(Java Native Interface)_02

JNI(Java Native Interface)_02 ndk开发常用术语 观察jni.h文件的c语言细节: 交叉编译 在一种平台下编译出能够在另外一种平台下运行二进制代码 平台(1,操作系统:windows linux mac os solaris 2,cpu x86 arm mips) 交叉编译原理 源代码--->编译---->动态库(.dll,.so)-->目标平台运行 windows 源代码编译成 linux,arm下的可执行文件 ndk开发工具 ndk (native de

JNI(Java Native Interface)_01

JNI(Java Native Interface)_01 习惯 1.技术是什么? 2.为什么要使用这个技术? 3.怎么使用? 4.实际怎么应用? jni 是什么 * jni (java native interface) * 两张不同编程语言之间通讯 java: 特点:一次编写,到处运行 java源代码--->.class--->JVM--->os c/c++ 源代码--->os(01) java(中国人)---JNI---c/c++(日本人) jni:两种不同编程语言之间的通讯

Java固有接口JNI(Java Native Interface)之HelloWorld

1.编写java程序 public class HelloWorld { public native void displayHelloWorld();//所有native关键词修饰的都是对本地的声明 static { System.loadLibrary("hello");//载入本地库 } public static void main(String[] args) { new HelloWorld().displayHelloWorld(); } } 2.编译 javac Hel

Mac下Java JNI (java native interface)调C

1.编写带有native声明的方法的Java类 2.使用javac命令编译编写的Java类 3.使用java -jni className 来生成后缀名为.h的头文件 4.使用其他语言(C.C++)实现本地方法 5.将本地方法编写的文件生成动态链接库 一代码:(不要带包路径) /** * native-0study * * @author xuedui.zhao * @create 2018-04-23 */public class HelloWorld { public native void

android 学习随笔二十七(JNI:Java Native Interface,JAVA原生接口 )

JNI(Java Native Interface,JAVA原生接口) 使用JNI可以使Java代码和其他语言写的代码(如C/C++代码)进行交互. 问:为什么要进行交互? 首先,Java语言提供的类库无法满足要求,且在数学运算,实时渲染的游戏上,音视频处理等方面上与C/C++相比效率稍低. 然后,Java语言无法直接操作硬件,C/C++代码不仅能操作硬件而且还能发挥硬件最佳性能. 接着,使用Java调用本地的C/C++代码所写的库,省去了重复开发的麻烦,并且可以利用很多开源的库提高程序效率.

java native interface JNI 调用Java方法

在上一篇文章中介绍了JNI,以及java调用JNI,这篇讲一下 JNI调用java方法. 通过使用合适的JNI函数,你可以创建Java对象,get.set 静态(static)和 实例(instance)的域,调用静态(static)和实例(instance)函数.JNI通过ID识别域和方法,一个域或方法的ID是任何处理域和方法的函数的必须参数. 下表列出了用以得到静态(static)和实例(instance)的域与方法的JNI函数.每个函数接受(作为参数)域或方法的类,它们的名称,符号和它们对

Java Programming Tutorial Java Native Interface (JNI)

1.  Introduction At times, it is necessary to use native codes (C/C++) to overcome the memory management and performance constraints in Java. Java supports native codes via the Java Native Interface (JNI). JNI is difficult, as it involves two languag

+Java中的native关键字浅析(Java+Native+Interface)++

JNI是Java Native Interface的 缩写.从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互.JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了. 使用java与本地已编译的代码交互,通常会丧失平台可移植性.但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件.操作系统进行交互,或者为了