JNI开发流程(1)

84 阅读12分钟

下面四个小程序用到的java类

public class Jni { static { System.loadLibrary("javacallc"); } /** * 求两个数字的和 * * @param x * @param y * @return */ public native int sum(int x, int y); /** * 将两个字符串拼接后返回 * * @param s * @return */ public native String sayHello(String s); /** * 将数组中的每个元素增加10 * * @param intArray * @return */ public native int[] increaseArrayEles(int[] intArray); /** * 应用: 检查密码是否正确, 如果正确返回200, 否则返回400 "123456" * @param pwd * @return */ public native int checkPwd(String pwd); }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

测试1:将传入的两个int值相加并返回

/** * 求两个数字的和 * * @param x * @param y * @return */ JNIEXPORT jint JNICALL Java_bruce_chang_javacallc_Jni_sum (JNIEnv *env, jobject jobj, jint int1, jint int2) { //jint可以直接进行算术运算 int sum = int1 + int2; //可直接将int类型数据作为jint返回 return sum; }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

测试2:将两个字符串拼接后返回

/** * 将两个字符串拼接后返回 * * @param s I am BruceChang * c I am SWJ * @return I am BruceChang add I am SWJ */ JNIEXPORT jstring JNICALL Java_bruce_chang_javacallc_Jni_sayHello (JNIEnv * env, jobject jobj, jstring js){ //将jstring类型的js转换为char*类型数据 char * fromJava = _JString2CStr(env,js); //c char * fromC = "add I am SWJ"; //将拼接两个char*类型字符串拼接在第一个上 strcat(fromJava, fromC); //将结果转换为jstring类型返回 return (*env)->NewStringUTF(env, fromJava); }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

这里面用到一个函数_JString2CStr 将字符串转换成字符指针

/** * 工具函数 * 把一个jstring转换成一个c语言的char* 类型. */ char* _JString2CStr(JNIEnv* env, jstring jstr) { char* rtn; jclass clsstring = (*env)->FindClass(env, "java/lang/String"); jstring strencode = (*env)->NewStringUTF(env,"GB2312"); jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B"); jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte("GB2312"); jsize alen = (*env)->GetArrayLength(env, barr); jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE); if(alen > 0) { rtn = (char*)malloc(alen+1); //"\0" memcpy(rtn, ba, alen); rtn[alen]=0; } (*env)->ReleaseByteArrayElements(env, barr, ba,0); return rtn; }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

测试3:将数组的每个元素增加10

/** * 将数组中的每个元素增加10 * * @param intArray * @return */ JNIEXPORT jintArray JNICALL Java_bruce_chang_javacallc_Jni_increaseArrayEles (JNIEnv * env, jobject jobj, jintArray arr){ //1. 得到数组的长度 //jsize (*GetArrayLength)(JNIEnv*, jarray); jsize length = (*env)->GetArrayLength(env, arr); //2. 得到数组 //jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*); jint* array = (*env)->GetIntArrayElements(env, arr, JNI_FALSE); //3. 遍历数组, 并将每个元素+10 int i; for(i=0;i<length;i++) { *(array+i) += 10; } //4. 返回数组 return arr; }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

测试4:检查密码是否正确

/** * 应用: 检查密码是否正确, 如果正确返回200, 否则返回400 "123456" * @param pwd * @return */ JNIEXPORT jint JNICALL Java_bruce_chang_javacallc_Jni_checkPwd (JNIEnv * env, jobject jobj, jstring string){ //1. 将jString转换为char* char* cs = _JString2CStr(env, string); char* pwd = "123456"; //2. 比较两个字符串是否相等 int result = strcmp(cs, pwd); //3. 根据比较的结果返回不同的值 if(result==0) { return 200; } return 400; }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

结果:

image

测试2,字符串的拼接,这个结果在不同的手机上显示效果还不太一样,在oppo r7上运行结果就是1、2、3、4、5,这个问题可能是程序不兼容导致的。

C调用Java方法


C调用java方法和java调用C的方法步骤一样,但C回调java方法的核心思想是利用反射的原理,其次还需要用到java中的javap -s命令来显示所有方法的签名信息,这个非常的重要,否则无法得到java类中的方法,从而也就无法实现C函数调用java方法。

显示方法签名的命令

E:\>cd E:\GithubDownload\TestNDK\ccalljava\src\main E:\GithubDownload\TestNDK\ccalljava\src\main>javah -d jni -classpath C:\AndroidDevelop\sdk\platforms\android-23\android.jar;E:\GithubDownload\TestNDK\ccalljava\build\intermediates\classes\debug com.bruce.chang.ccalljava.Jni E:\GithubDownload\TestNDK\ccalljava\src\main>javap -s -classpath C:\AndroidDevelop\sdk\platforms\android-23\android.jar;E:\GithubDownload\TestNDK\ccalljava\build\intermediates\classes\debug com.bruce.chang.ccalljava.Jni Compiled from "Jni.java" public class com.bruce.chang.ccalljava.Jni { public com.bruce.chang.ccalljava.Jni(); descriptor: ()V public native void callbackHelloFromJava(); descriptor: ()V public native void callbackAdd(); descriptor: ()V public native void callbackPrintString(); descriptor: ()V public native void callbackSayHello(); descriptor: ()V public void helloFromJava(); descriptor: ()V public int add(int, int); descriptor: (II)I public void printString(java.lang.String); descriptor: (Ljava/lang/String;)V public static void sayHello(java.lang.String); descriptor: (Ljava/lang/String;)V static {}; descriptor: ()V } E:\GithubDownload\TestNDK\ccalljava\src\main>

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

一般调用步骤

  1. 加载类得到class对象

  2. 得到对应方法的Method对象

  3. 创建类对象

  4. 调用方法

测试1:回调一般方法(无参无返回)

java端方法

public native void callbackHelloFromJava();

  • 1

java端被回调方法

public void helloFromJava() { Log.e("TAG", "helloFromJava()"); }

  • 1

  • 2

  • 3

C端函数

void Java_com_bruce_chang_ccalljava_Jni_callbackHelloFromJava (JNIEnv * env, jobject obj) { //1. 加载类得到jclass对象: //jclass (*FindClass)(JNIEnv*, const char*); jclass jc = (*env)->FindClass(env, "com/bruce/chang/ccalljava/Jni"); //2. 得到对应方法的Method对象 : GetMethodId() //jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*) jmethodID method = (*env)->GetMethodID(env, jc, "helloFromJava", "()V"); //3. 创建类对象 //jobject (*AllocObject)(JNIEnv*, jclass); jobject obj2 = (*env)->AllocObject(env, jc); //4. 调用方法 (*env)->CallVoidMethod(env, obj2, method); }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

测试2:回调带int参数方法

java端方法

public native void callbackAdd();

  • 1

java端被回调方法

public int add(int x, int y) { Log.e("TAG", "add() x=" + x + " y=" + y); return x + y; }

  • 1

  • 2

  • 3

  • 4

C端函数

void Java_com_bruce_chang_ccalljava_Jni_callbackAdd(JNIEnv * env, jobject obj){ //1. 加载类得到class对象 jclass jc = (*env)->FindClass(env, "com/bruce/chang/ccalljava/Jni"); //2. 得到对应方法的Method对象 jmethodID method = (*env)->GetMethodID(env, jc, "add", "(II)I"); //3. 创建类对象 jobject obj2 = (*env)->AllocObject(env, jc); //4. 调用方法 (*env)->CallIntMethod(env, obj2, method, 3, 4); }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

测试3:回调带String参数方法

java端方法

public native void callbackPrintString();

  • 1

java端被回调方法

public void printString(String s) { Log.e("TAG", "C中输入的:" + s); }

  • 1

  • 2

  • 3

C端函数

void Java_com_bruce_chang_ccalljava_Jni_callbackPrintString(JNIEnv * env, jobject obj){ //1. 加载类得到class对象 jclass jc = (*env)->FindClass(env, "com/bruce/chang/ccalljava/Jni"); //2. 得到对应方法的Method对象 jmethodID method = (*env)->GetMethodID(env, jc, "printString", "(Ljava/lang/String;)V"); //3. 创建类对象 jobject obj2 = (*env)->AllocObject(env, jc); //4. 调用方法 jstring js = (*env)->NewStringUTF(env, "I from C"); (*env)->CallVoidMethod(env, obj2, method, js); }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

测试4:回调静态方法

java端方法

public native void callbackSayHello();

  • 1

java端被回调方法

public static void sayHello(String s) { Log.e("TAG", "我是java代码中的JNI." + "java中的sayHello(String s)静态方法,我被C调用了:" + s); }

  • 1

  • 2

  • 3

  • 4

C端函数

void Java_com_bruce_chang_ccalljava_Jni_callbackSayHello(JNIEnv * env, jobject obj){ //1. 加载类得到class对象 jclass jc = (*env)->FindClass(env, "com/bruce/chang/ccalljava/Jni"); //2. 得到对应方法的Method对象 jmethodID method = (*env)->GetStaticMethodID(env, jc, "sayHello", "(Ljava/lang/String;)V"); //3. 调用方法 jstring js = (*env)->NewStringUTF(env, "I from C"); (*env)->CallStaticVoidMethod(env, jc, method, js); }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

结果:

image

小应用:回调更新UI的方法

java端方法,在MainActivity中写

/** * 让C代码调用MainActivity中的showToast方法 */ public native void callbackShowToast();

  • 1

  • 2

  • 3

  • 4

java端被回调方法

public void showToast() { Toast.makeText(MainActivity.this, "this is a toast!!!", Toast.LENGTH_SHORT).show(); }

  • 1

  • 2

  • 3

C端函数

/** * 让C代码调用MainActivity中的showToast方法 * obj 谁调用了当前Java_com_bruce_chang_ccalljava_Jni_callbackShowToast对应的java方法就是就是谁的实例, * 该方法如果放在Jni这个类中就是是Jni.this,如果放在MainActivity中就是MainActivity.this */ void Java_com_bruce_chang_ccalljava_MainActivity_callbackShowToast(JNIEnv * env, jobject obj){ //1. 加载类得到class对象 jclass jc = (*env)->FindClass(env, "com/bruce/chang/ccalljava/MainActivity"); //2. 通过方法名和方法签名得到对应方法的Method对象 jmethodID method = (*env)->GetMethodID(env, jc, "showToast", "()V"); //3. 创建类对象 // jobject obj2 = (*env)->AllocObject(env, jc); //4. 调用方法 (*env)->CallVoidMethod(env, obj, method); }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

点击调用callbackShowToast方法

// jni.callbackShowToast();不能调用jni中的callbackShowToast方法,这样会报空指针错误,因为发射得到的是MainActivity的类, // 并不是Activity,在执行showToast方法的时候就出错了 MainActivity.this.callbackShowToast();

  • 1

  • 2

  • 3

结果:

image

切记切记

通过本实例可以发现,通过C代码调用活动中的方法的时候,一定要在活动中调用native方法,否则在C回调的时候就会出现空指针的错误。

JNINativeInterface的相关函数指针


//功能: 加载类得到类对象 //返回: jni的class类型 jclass (*FindClass)(JNIEnv*, const char*)

  • 1

  • 2

  • 3

//功能: 得到对应方法的Method对象 jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*)

  • 1

  • 2

//功能: 创建对象 jobject (*AllocObject)(JNIEnv*, jclass)

  • 1

  • 2

//功能: 调用没有返回值的方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...)

  • 1

  • 2

  • 3

//功能: 调用返回int值的方法 jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...)

  • 1

  • 2

//功能: 得到静态方法的method jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*)

  • 1

  • 2

  • 3

//功能: 调用静态方法 void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...)

  • 1

  • 2

  • 3

//功能: 将C中的字符串转换为JNI中的jstring类型 //第二个: 被转换的字符串 jstring (*NewStringUTF)(JNIEnv*, const char*)

  • 1

  • 2

  • 3

  • 4

//功能: 将第二个字符串连接到第一个字符串上 string.h---char* strcat(char *, const char *);

  • 1

  • 2

  • 3

//功能: 得到jni类型数组的长度(元素个数) jsize (*GetArrayLength)(JNIEnv*, jarray);

  • 1

  • 2

  • 3

//功能: 得到jni数组中所有元素的指针 //第二个: jni中的int数组 第三个: 是否返回一个复制的数组 jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);

  • 1

  • 2

  • 3

//参数为两个字符串 //第一个与第二个相等, 返回0 第一个大于第二个, 返回大于0 第一个小于第二个, 返回小于0 string.h---int strcmp(const char *, const char *)

  • 1

  • 2

  • 3

  • 4

NDK开发综合案例

=======================================================================

案例1: 美图秀秀


步骤

  1. 创建工程MTXX

  2. 把对应的.so文件拷贝到java/main/jniLibs目录。。armeabi/libmtimage-jin.so

  3. 创建一个类叫做JNI.java并且要在com.mt.mtxx.image包下创建

  4. 加载动态链接库,System.loadLibrary(“mtimage-jni”)

  5. 写布局文件和实现各个效果的点击事件

  6. 处理图片相关的工作

  • 6.1把图片转换成矩阵(数组)

  • 6.2把数组传入给C代码处理

  • 6.3把处理好的数组重新生成图片

  • 6.4把图片显示

按照上面的步骤一步一步的来,布局文件非常简单,就不写出来了。

布局效果

image

java程序中调用处理

  1. 加载Jni程序

JNI jni = new JNI();

  • 1
  1. 高亮效果

public void lomoHDR(View view) { //6.1,把图片转换成数组 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.fbb); //装图片的像数 int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()]; /** * 参数 pixels 接收位图颜色值的数组 offset 写入到pixels[]中的第一个像素索引值 stride pixels[]中的行间距个数值(必须大于等于位图宽度)。可以为负数 x 从位图中读取的第一个像素的x坐标值。 y 从位图中读取的第一个像素的y坐标值 width 从每一行中读取的像素宽度 height   读取的行数   异常 */ bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight()); //6.2,把数组传入给C代码处理 jni.StyleLomoHDR(pixels, bitmap.getWidth(), bitmap.getHeight()); // 6.3,把处理好的数组重新生成图片 bitmap = Bitmap.createBitmap(pixels, bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); // 6.4,把图片像数 iv_icon.setImageBitmap(bitmap); }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  1. 黑白效果

public void lomoC(View view) { //6.1,把图片转换成数组 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.fbb); //装图片的像数 int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()]; bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight()); //6.2,把数组传入给C代码处理 jni.StyleLomoC(pixels, bitmap.getWidth(), bitmap.getHeight()); // 6.3,把处理好的数组重新生成图片 bitmap = Bitmap.createBitmap(pixels, bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); // 6.4,把图片像数 iv_icon.setImageBitmap(bitmap); }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  1. 怀旧效果

public void lomoB(View view) { //6.1,把图片转换成数组 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.fbb); //装图片的像数 int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()]; bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight()); //6.2,把数组传入给C代码处理 jni.StyleLomoB(pixels, bitmap.getWidth(), bitmap.getHeight()); // 6.3,把处理好的数组重新生成图片 bitmap = Bitmap.createBitmap(pixels, bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); // 6.4,把图片像数 iv_icon.setImageBitmap(bitmap); }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  1. 还原

iv_icon.setImageResource(R.mipmap.fbb);

  • 1

剩下的四种效果就不说明了,稍后看一下结果。

结果(只能在arm架构的处理器上运行,x86的处理器的手机是不能运行该程序的):

image

案例2: 锅炉压力系统


步骤

  1. 创建一个module名字叫做GuoLu,

1.1 在MainActivity中写得到锅炉压力值的native方法—getPressure();

1.2 在build.gradle文件中配置生成.so文件的名称

defaultConfig { applicationId "com.bruce.chang.guolu" minSdkVersion 15 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" ndk{ moduleName "GuoLu" //so文件: lib+moduleName+.so abiFilters "armeabi", "armeabi-v7a", "x86" //cpu的类型 } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  1. 分析实现的原理

  2. 在C代码中写锅炉的压力值,返回给java

/** 得到锅炉的压力值 */ int pressure = 20; int getPressure(){ int incease = rand()%20; pressure += incease; return pressure; }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  1. 在视图中动态绘制

GuoLu.c代码

//

// Created by Administrator on 2016/4/19.

//

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

include <jni.h>

===============

/**

得到锅炉的压力值

*/

int pressure = 20;

int getPressure(){

int incease = rand()%20;

pressure += incease;

return pressure;

}

/**

* 从锅炉感应器中得到锅炉压力值

*/

jint Java_com_bruce_chang_guolu_MainActivity_getPressure(JNIEnv *env, jobject instance) {

int pressur = getPressure();

return pressur;

}

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

MainActivity.java中调用

public class MainActivity extends AppCompatActivity { { System.loadLibrary("GuoLu"); } PressureView pressureView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); pressureView = new PressureView(MainActivity.this); setContentView(pressureView); new Thread(new Runnable() { @Override public void run() { while (true) { SystemClock.sleep(500); int pressure = Math.abs(getPressure()); pressureView.setPressure(pressure); //如果压力大于220 if (pressure > 220) { break; } } } }).start(); } /** * native代码 * 调用C代码中的对应方法 * * @return */ public native int getPressure(); }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

自定义view—PressureView来控制显示的过程

public class PressureView extends View { private int pressure; private Paint mPaint; public PressureView(Context context) { super(context); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setTextSize(50); } public void setPressure(int pressure) { this.pressure = pressure; // invalidate();//在主线程中运行 postInvalidate();//ondraw()执行 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //1:如果压力值大于220,就绘制文本,显示锅炉爆炸了,快跑 if (pressure > 220) { mPaint.setColor(Color.RED); canvas.drawText("要爆炸了,快跑炮", 10, getHeight() / 2, mPaint); } else { //2:正常和提示的情况 //设置背景颜色为灰色 mPaint.setColor(Color.GRAY); canvas.drawRect(10, 10, 60, 260, mPaint); canvas.drawText("pressure=="+pressure, 10, getHeight() / 2, mPaint); //2.1 如果是小于200正常显示并且设置画笔颜色绿色 if (pressure < 200) { mPaint.setColor(Color.GREEN); canvas.drawRect(10, 260-pressure, 60, 260, mPaint); } else if (pressure>200){ //2.2 如果是大于200警示显示给看护者,并且设置画笔颜色红色 mPaint.setColor(Color.YELLOW); canvas.drawRect(10, 260-pressure, 60, 260, mPaint); } } } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37