在Android中用C/C++开发一部分功能时,有时候要把参数传到java层,java层来做相应的处理和更新UI。
所以安卓有一个JNI来给开发者们调用这些数据和处理。但是这样会损失一些性能,第一,java跨平台的优势没有了,第二,当
c/c++写的代码出问题时候,程序会崩溃,不容易找错,所以建议调用时候要多加LOGI打印,在关键调用地方记得要添加返回
值,这样能够省掉很多时间来找错误。
这样才能把信息传递给java层。当C/C++文件很多时,里面线程也很多时, 这时就需要我们使用统一的回调函数来处理了,不然
会很混乱的
实现思路:
1、jni里面调用java方法的大致步骤是:根据jobject获取jclass(静态方法就不用这一步了)--> 获取jmethodid --> 调用方法。
2、jni里面调用java方法的环境分为2种。
第一种:在env所在线程调用java方法,这种情况不需要做特殊处理,直接按照步骤执行即可。
第二种:在pthread子线程调用java方法,这种情况下就需要做处理了。在jni中,子线程中是不能直接调用JNIEnv对象的,也不能直接调用env线程中的jobject对象,
因为:jni中,JNIEnv是和线程相关的,每一个native方法所在线程就有一个当前线程相关的JNIEnv对象,而pthread线程中是不能调用native方法所在线程的JENnv对象的,
解决办法是:利用JavaVM虚拟机,JavaVM是和进程相关的,一个进程里面的JavaVM都是同一个,所以在pthread线程中就可以通过JavaVM来获取(AttachCurrentThread)
当前线程的JNIEnv指针,然后就可以使用JNIEnv指针操作数据了;还有在pthread线程中调用jobject对象时,首先需要把native线程里面的jobject创建全局引用(env->NewGlobalRef(jobj)),
其返还的jobject对象就可以在程序中使用了。
3、在JNI_OnLoad中获取我们需要的JavaVM指针。
创建.h文件
void WlListener(JavaVM* vm, _JNIEnv *jenv, jobject obj);
void onError(int type, int code, const char *msg);
JavaVM* jvm;//java虚拟机
_JNIEnv *jenv;//native线程env对象
jobject jobj;//全局对象
jmethodID jmid;//java 方法id,可以根据实际情况创建多个。
创建.cpp文件
void WlListener(JavaVM* vm, _JNIEnv *env, jobject obj)
{
jvm = vm;
jenv = env;
jobj = obj;
jclass classvideo = env->GetObjectClass(jobj);
if(!classvideo)
{
// LOGD("get class error...");
}
jmid = env->GetMethodID(classvideo,"onError","(ILjava/lang/String;)V");
if(!jmid)
{
// LOGD("get jmethodIO error...:);
return;
}
}
void onError(int type, int code, const char *msg) {
if(type == 0)
{
jstring jmsg = jenv->NewStringUTF(msg);
jenv->CallVoidMethod(jobj, jmid, code, jmsg);
jenv->DeleteLocalRef(jmsg);
}
else if(type == 1)
{
JNIEnv *env;
jvm->AttachCurrentThread(&env, 0);
jstring jmsg = env->NewStringUTF(msg);
env->CallVoidMethod(jobj, jmid, code, jmsg);
env->DeleteLocalRef(jmsg);
jvm->DetachCurrentThread();
}
其中:jvm参数是为了获取子线程中的JNIEnv;jenv参数是native线程中的,在native线程中使用;
jobj是全局对象;jmid是要调用的java层的方法id,还可以有其他方法。
2.然后创建jni层native-lib.cpp文件通过JNI_OnLoad获取JavaVM:
extern "C"
JNIEXPORT void JNICALL
Java_com_example_dell_sample_testJNI_UDPVideoRecvThreadID(
JNIEnv* env,
jobject jobj) {
WlListener(jvm, env, env->NewGlobalRef(jobj));//转化成全局变量.
LOGI("JNIENV thread running START1...");
//onError(0, 100, "JNIENV thread running success!");
LOGI("create child thread START1...");
pthread_create(&UDPVideoRecvThreadID, NULL, UdpVideoRecvTask,(void *)&UDP_VideoSocket);
}
3.java方法实现
//3、回调线程
public native void callbackThread();
private OnErrorListener onErrorListener;
public void setOnErrorListener(OnErrorListener onErrorListener) {
this.onErrorListener = onErrorListener;
}
//Jni调用此方法,把结果返回到java层
public void onError(int code, String msg)
{
if(onErrorListener != null)
{
onErrorListener.onError(code, msg);
}
}
public interface OnErrorListener
{
void onError(int code, String msg);
}
4.java中activity实现
m_test.setOnErrorListener(new testJNI.OnErrorListener() {
@Override
public void onError(int code, String msg) {
Log.d("lsx test", "code: " + code + ", msg: " + msg);
Message message = Message.obtain();
message.what = code;
message.obj = msg;
handler.sendMessage(message);
}
});
//tv.setText(m_test.stringFromJNI());
// m_test.init(str);
//m_test.init(str);
// m_test1.main();
}
class MyServiceConn implements ServiceConnection {
// 服务被绑定成功之后执行
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// IBinder service为onBind方法返回的Service实例
binder = (MyService.MyBinder) service;
binder.getService().setDataCallback(new MyService.DataCallback() {
//执行回调函数
@Override
public void dataChanged(String str) {
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putString("str", str);
//Log.d("Mac",str);
msg.setData(bundle);
//发送通知
handler.sendMessage(msg);
//m_test.init(str);
//m_test.init();
}
});
}
public void jniCallback(View view) {
// ppNet.callbackThread();
m_test.UDPVideoRecvThreadID();
}
Handler handler = new Handler()
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Toast.makeText(MainActivity.this, (String)msg.obj, Toast.LENGTH_SHORT).show();
}
};
这是一个c++写的接收mjpeg视频流然后用androidJNI调用的小插曲,文章有借鉴别人的d地方,时间赶,写的也比较随便,还有
android读取设备信息利用jni给到c++中,还有mjpeg解码等等内容等项目做完了再一段一段的更新分享。希望能够帮助到需要的
人,有希望交流的欢迎留言!
借鉴作者地址https://blog.csdn.net/ywl5320/article/details/78739211#comment