Android JNI
- JNI最为C++和java在Android中的桥梁,在整个开发过程中都是至关重要的,也是必须要去熟悉的地方。
- 本篇主要记录下自己在学习的JNI中过程,本篇只是在单一主线程进行调用,下一篇将介绍多线程进行调用的情况,也希望可以帮助到有需要的人,仅此而已。
- Java调用C++代码
a. 在日常中对于一些对性能要求更高的地方,经常会采用C++来进行完成,那么此时就涉及到要使用java调用C++层API完成相应的动作。
b. 新建一个NativiUtils类完成具体API的设计,不和MainActivity混在一起
c. javc调用C++过程其实很简单,只是一个C++层具体代码的实现
d. 下面的环境是在Android Studio中进行操作,C++编译采用cmake完成编译。
MainActivity.java
package com.example.blogdemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
final NativeUtils nativeUtils = new NativeUtils();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
// 这里进行将C++层代码进行一个回显
TextView textView = findViewById(R.id.sample_text);
textView.setText(nativeUtils.jniJavaCallcPlus("skinWhite blog"));
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
}
NativeUtils.java
package com.example.blogdemo;
// TODO
// 1. 完成native方法的设计
// 2. 实现该方法
public class NativeUtils {
// 这里设计native的API,至于C++层的方法头,可以使用alt+enter自动生成
public native String jniJavaCallcPlus(String Helloname);
}
native-lib.cpp
#include <jni.h>
#include <string>
#include <iostream>
// TODO
// 1. C++层代码具体实现
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_momo_blogdemo_NativeUtils_jniJavaCallcPlus(JNIEnv *env, jobject instance,
jstring Helloname_) {
// 1. C++层的代码实现
jboolean isCopy;
std::string helloName = env->GetStringUTFChars(Helloname_,&isCopy);
return env->NewStringUTF(helloName.data());
}
- C++调用Java代码
a. 应为C++层不能通过native直接调用java代码,所以需要进行一些而外的操作
b. 其次本demo不考虑多线程情况下的调用,将在下一篇进行多线程的介绍。
c. 在实现C++调用java时只需按照下文5步操作,但是要完成JNI层参数对照。
d. 在获取类的字节码码时,注意中间用’ / ‘,而不是’ _ '。
f. 如果要自己完成Cpp文件的话,注意要在CmakeLists.txt中倒入源文件路径,在MainActivity记得静态加载库。
MainActivity.java
package com.example.blogdemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
final NativeUtils nativeUtils = new NativeUtils();
public static TextView textView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
textView = findViewById(R.id.sample_text);
nativeUtils.jniJavaCallcPlus("SkinWhite blog");
}
}
NativeUtils.java
package com.example.momo.blogdemo;
import android.os.Handler;
import android.os.Looper;
public class NativeUtils {
public static Handler uiHandler = new Handler(Looper.getMainLooper());
// Java层调用C++
public native void jniJavaCallcPlus(String Helloname);
// C++层调用Java
public void jnicPlusCallJava(final String Helloname){
// 具体实现(UI刷新)
uiHandler.post(new Runnable() {
@Override
public void run() {
MainActivity.textView.setText(Helloname);
}
});
}
}
#include <jni.h>
#include <string>
#include <iostream>
extern "C"
JNIEXPORT void JNICALL
Java_com_example_momo_blogdemo_NativeUtils_jniJavaCallcPlus(JNIEnv *env, jobject instance,
jstring Helloname_) {
// TODO
// 1. 拿到class的字节码
jclass cls = env->FindClass("com/example/momo/blogdemo/NativeUtils");
// 2. 获取methodId,最后一个参数可以参照JNI对照表
jmethodID mid = env->GetMethodID(cls,"jnicPlusCallJava","(Ljava/lang/String;)V");
// 3. 实例化对象
jobject obj = env->AllocObject(cls);
// 4. 构造方法参数(因为本身即使jstring对象,所以不用转换)
// 5. 调用方法
env->CallVoidMethod(obj,mid,Helloname_);
}
> 上述代码其实是是C++的异步调用了Java层。整个过程是Java层先调用一个nativa方法,native方法里回调java层的代码,完成C++调用java的实现。