JNI回调的Android(NDK)实现,带有NDK和回调的Observer- Subscriber模式,自写的EventBus或Rx
... 我知道“里面没有用户可维修的零件”。 我想看看那里是什么。
-俄罗斯嵌套娃娃到最深处。 真的,奥罗斯科吗? 胡安没有看俄罗斯嵌套娃娃是什么。
“这是垃圾,顾教授。” 谁需要它-搞砸了吗?
“彩虹的尽头” Vinge Vernor
有很多Android应用程序将C ++和Java代码结合在一起。 Java实现业务逻辑,而C ++完成通常在音频处理中发现的所有计算工作。 音频流在内部某处进行处理,楼上显示带有油门和离合器的制动器,以及各种有趣图片的数据。
好吧,由于ReactiveX已经很熟悉了,为了不改手,并以熟悉的方式使用JNI地牢,您通常需要在带有NDK的项目中实现Observer模式。 好吧,与此同时,代码的可理解性 考古学家 那些不幸“理解别人的代码”的人增加了。
因此,最好的学习方法是自己做。
假设我们热爱并知道如何写自行车。 结果是:
- 像是从C ++代码回发给签名者一样;
- 以本机代码进行处理的管理,也就是说,在没有订阅者且没有人发送的情况下,我们可能不会被迫解决。
- 不同的JVM之间可能需要数据传输;
- 为了避免起床两次,同时在项目流中发送消息。
完整的工作代码可在GitHub上获得 。 本文仅提供摘录。
一点理论和历史
最近,我在RX会议上,对以下问题感到惊讶:ReactiveX有多快以及它如何工作。
对于ReactiveX,我只能说对于Java,它的速度在很大程度上取决于它的使用方式;如果使用正确,它的速度就足够了。
我们的自行车重量更轻,但是例如,如果您需要一个消息队列(如可流动的),则需要自己编写。 因为您知道所有故障都是您的。
理论上的一点: 观察者-订阅者模式是一种机制,它允许对象接收有关其他对象状态变化的警报,从而观察它们。 这样做是为了减少软件组件之间的连接性和依赖性,从而可以更有效地使用和测试它们。 语言概念所基于的生动代表就是一切-Smalltalk,全部基于发送消息的思想。 受影响的Objective-C。
实作
让我们尝试DIY的最佳传统,可以说是“闪烁LED”。 如果使用JNI,则在Android NDK世界中,可以在任何线程中异步请求Java方法。 这就是我们用来构建“观察者”的东西。
该演示项目基于Android Studio中的新项目模板。
这是一种自动生成的方法。 他评论说:
现在为您自己。 第一步是nsubscribeListener
方法。
private native void nsubscribeListener(JNIListener JNIListener);
它允许C ++代码获取到Java代码的链接,以实现对实现JNIListener.
接口的对象的回调JNIListener.
public interface JNIListener { void onAcceptMessage(String string); void onAcceptMessageVal(int messVal); }
值将被转移到其方法的执行中。
为了有效地缓存到虚拟机的链接,我们还将链接保存到对象。 我们为此获得了全球链接。
Java_ua_zt_mezon_myjnacallbacktest_MainActivity_nsubscribeListener(JNIEnv *env, jobject instance, jobject listener) { env->GetJavaVM(&jvm);
立即计数并保存指向方法的链接。 这意味着完成回调所需的操作较少。
jclass clazz = env->GetObjectClass(store_Wlistener); jmethodID store_method = env->GetMethodID(clazz, "onAcceptMessage", "(Ljava/lang/String;)V"); jmethodID store_methodVAL = env->GetMethodID(clazz, "onAcceptMessageVal", "(I)V");
订户数据存储为ObserverChain
类记录。
class ObserverChain { public: ObserverChain(jweak pJobject, jmethodID pID, jmethodID pJmethodID); jweak store_Wlistener=NULL; jmethodID store_method = NULL; jmethodID store_methodVAL = NULL; };
将订户保存到动态数组store_Wlistener_vector。
ObserverChain *tmpt = new ObserverChain(store_Wlistener, store_method, store_methodVAL); store_Wlistener_vector.push_back(tmpt);
现在介绍如何传输来自Java代码的消息。
发送到nonNext方法的消息将发送给所有签名者。
private native void nonNext(String message);
实现方式:
Java_ua_zt_mezon_myjnacallbacktest_MainActivity_nonNext(JNIEnv *env, jobject instance, jstring message_) { txtCallback(env, message_); }
函数txtCallback(env,message_); 发送消息给所有签署者。
void txtCallback(JNIEnv *env, const _jstring *message_) { if (!store_Wlistener_vector.empty()) { for (int i = 0; i < store_Wlistener_vector.size(); i++) { env->CallVoidMethod(store_Wlistener_vector[i]->store_Wlistener, store_Wlistener_vector[i]->store_method, message_); } } }
要转发来自C ++或C代码的消息,我们使用test_string_callback_fom_c函数
void test_string_callback_fom_c(char *val)
她从一开始就检查是否有订户。
if (store_Wlistener_vector.empty()) return;
很容易看出,使用相同的txtCallback函数发送消息:
void test_string_callback_fom_c(char *val) { if (store_Wlistener_vector.empty()) return; __android_log_print(ANDROID_LOG_VERBOSE, "GetEnv:", " start Callback to JNL [%d] \n", val); JNIEnv *g_env; if (NULL == jvm) { __android_log_print(ANDROID_LOG_ERROR, "GetEnv:", " No VM \n"); return; }
在MainActivity中,我们创建两个文本视图和一个EditView。
<TextView android:id="@+id/sample_text_from_Presenter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:padding="25dp" android:text="Hello World!from_Presenter" app:layout_constraintBottom_toTopOf="parent" app:layout_constraintEnd_toStartOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/sample_text_from_act" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="Hello World from_ac!" app:layout_constraintBottom_toTopOf="parent" app:layout_constraintStart_toStartOf="@+id/sample_text_from_Presenter" app:layout_constraintTop_toTopOf="parent" /> <EditText android:id="@+id/edit_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toTopOf="parent" app:layout_constraintStart_toStartOf="@+id/sample_text_from_act" app:layout_constraintTop_toTopOf="parent" />
在OnCreate中,我们将View与变量绑定,并描述在EditText中更改文本时,将向订阅者发送一条消息。
mEditText = findViewById(R.id.edit_text); mEditText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { nonNext(charSequence.toString()); } @Override public void afterTextChanged(Editable editable) { } }); tvPresenter = (TextView) findViewById(R.id.sample_text_from_Presenter); tvAct = (TextView) findViewById(R.id.sample_text_from_act);
我们开始并注册订户:
mPresenter = new MainActivityPresenterImpl(this); nsubscribeListener((MainActivityPresenterImpl) mPresenter); nlistener = new JNIListener() { @Override public void onAcceptMessage(String string) { printTextfrActObj(string); } @Override public void onAcceptMessageVal(int messVal) { } }; nsubscribeListener(nlistener);
看起来像这样:

完整的工作代码位于GitHub https://github.com/NickZt/MyJNACallbackTest
在评论中让我们知道要详细描述的内容。