码迷,mamicode.com
首页 > 编程语言 > 详细

JNI(Java Native Interface)_03

时间:2015-04-03 17:29:29      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:jni

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、运行

技术分享

JNI(Java Native Interface)_03

标签:jni

原文地址:http://blog.csdn.net/faith_yee/article/details/44856237

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!