标签:jni
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, java程序员定义好native
* 2, java程序员生成jni规范
* 3, 找一个c程序员写好代码实现
* 4, 通过jni调用(.so)
* 1,c代码已经写好
* 2,根据c代码定义native方法
* 3,jni规范
* 4,调用(.so)
* 1. .so文件已经生成
* 2, 拿到jni规范
* 3, 直接调用
锅炉监控的由来:
北方天气很冷,所以需要锅炉加热来取暖,但是锅炉加热如果不监控的话,会产生温度过高而导致爆炸,而人为的监控比较麻烦,所以我们就可以给锅炉加上一个电子监控器(C语言控制的),而当监控器监控到温度过高,就可以给通过与Java语言通信而给用户发送信息告知,如果C与java不通信的话,单靠C语言实现给设备发送信息,这实现难度难以估计。这就是这个案例的由来
案例目的:
1、演示在jni文件夹下的c程序如何调用别的c程序的方法
2、为完成锅炉监控的全功能实现做铺垫
案例步骤:
右键工程-->android tools-->add native support->输入动态库名字->点击确定
/**
* 该方法获取锅炉发来的监控数据,这里为了模拟就采用C语言调用伪随机数发来的数据
* @return
*/
public native int getPress();
这一步和之前的不一样了,这里需要在jni自动生成的c文件里调用另外一个c文件里的方法,这样可以降低耦合性。可以另程序员工作量大大减低
guolu.c
#include <stdio.h>
#include<stdlib.h>
/*
*/
int getNumber()
{
return rand() % 100;//锅炉压力表
}
main()
{
printf("%d\n",getNumber());
system("pause");
}
右键工程--》properties->c/c++ general->paths and symbols 选择includes 点击add 把I:\android-ndk-r9\platforms\android-9\arch-arm\usr\include 保存
guolu1.c
#include <jni.h>
jint Java_com_itheima_guolu1test_MainActivity_getPress
(JNIEnv * env, jobject obj)
{
return getNumber();//可以直接调用了
}
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;
}
}
案例目的:
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、运行
案例目的
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、在手机上测试布局是否满意
案例目的:
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;
}
}
案例结果:
案例目的:
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卸载后
案例目的:
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
原文地址:http://blog.csdn.net/faith_yee/article/details/44856237