تطبيق Android (NDK) لردود اتصال JNI ، نمط المراقب - المشترك مع NDK ورد الاتصال ، EventBus أو Rx المكتوبة ذاتيًا
... حصلت عليه "لا توجد أجزاء يمكن للمستخدم صيانتها في الداخل." أريد أن أرى ما هو موجود.
- دمى التعشيش الروسية حتى الأعماق. حقا ، أوروزكو؟ لم ينظر خوان إلى ما هي دمية التعشيش الروسية.
"إنها قمامة يا أستاذ قو." من يحتاجها - للتلاعب بهذا؟
"نهاية قوس قزح" فينج فيرنور
هناك عدد غير قليل من تطبيقات Android التي تجمع بين C ++ و Java code. تقوم Java بتنفيذ منطق الأعمال ، ويقوم C ++ بجميع أعمال الحوسبة ، غالبًا ما توجد في المعالجة الصوتية. تتم معالجة دفق الصوت في مكان ما بالداخل ، ويتم عرض الفرامل مع الغاز والقابض في الطابق العلوي ، والبيانات لجميع أنواع الصور المضحكة.
حسنًا ، منذ ReactiveX ، إنه أمر مألوف بالفعل ، حتى لا تغير يدك ، والعمل مع زنزانة JNI بطرق مألوفة ، تحتاج بانتظام إلى تنفيذ نمط Observer في المشاريع مع NDK. حسنًا ، في الوقت نفسه ، فهم الرمز علماء الآثار أولئك الذين هم غير محظوظين "لفهم رمز شخص آخر" يزداد.
لذا ، فإن أفضل طريقة لتعلم شيء ما هي أن تفعل ذلك بنفسك.
لنفترض أننا نحب ونعرف كيف نكتب دراجاتنا. وماذا سنحصل نتيجة لذلك:
- شيء من هذا القبيل إعادة النشر من كود C ++ إلى الموقعين ؛
- إدارة المعالجة في التعليمات البرمجية الأصلية ، أي أننا قد لا نضطر إلى المستوطنات عندما لا يكون هناك مشتركون ولا يوجد أحد لإرسالهم ؛
- قد يكون من الضروري نقل البيانات بين JVMs المختلفة ؛
- ولكي لا تستيقظ مرتين ، في نفس الوقت ترسل رسائل داخل تدفقات المشروع.
كود العمل الكامل متاح على جيثب . تقدم المقالة مقتطفات منه فقط.
القليل من النظرية والتاريخ
لقد كنت مؤخرًا في اجتماع RX واستغربت عدد الأسئلة حول: مدى سرعة ReactiveX وكيف يعمل على الإطلاق.
بالنسبة لـ ReactiveX ، لا يسعني إلا أن أقول أن سرعته بالنسبة لـ Java تعتمد إلى حد كبير على مدى معقولية استخدامها ؛ إذا تم استخدامها بشكل صحيح ، فإن سرعتها كافية.
دراجتنا خفيفة الوزن كثيرًا ، ولكن إذا كنت بحاجة ، على سبيل المثال ، إلى قائمة انتظار الرسائل (مثل التدفق) ، فأنت بحاجة إلى كتابتها بنفسك. لأنك تعلم أن كل مواطن الخلل هي لك وحدك.
القليل من النظرية: نمط المراقب - المشترك هو آلية تسمح لكائن بتلقي تنبيهات حول التغييرات في حالة الأشياء الأخرى وبالتالي مراقبتها. يتم ذلك لتقليل الاتصال والتبعيات بين مكونات البرامج ، مما يسمح باستخدامها واختبارها بشكل أكثر كفاءة. يمثل كل شيء ممثلًا حيًا يتم فيه بناء مفهوم اللغة على هذا - Smalltalk ، وكلها تستند إلى فكرة إرسال الرسائل. الهدف المتأثر - ج.
التنفيذ
دعنا نجرب في أفضل تقاليد DIY ، إذا جاز التعبير ، "وميض LED". إذا كنت تستخدم JNI ، في عالم Android NDK ، يمكنك طلب طريقة Java بشكل غير متزامن ، في أي موضوع. هذا ما نستخدمه لبناء "مراقبنا".
يعتمد المشروع التجريبي على قالب المشروع الجديد من Android Studio.
هذه طريقة تم إنشاؤها تلقائيًا. وعلق:
الآن لنفسك. الخطوة الأولى هي طريقة nsubscribeListener
.
private native void nsubscribeListener(JNIListener JNIListener);
يسمح لكود C ++ بالحصول على رابط إلى كود جافا لتمكين رد الاتصال بكائن يقوم بتنفيذ واجهة 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 code ، نستخدم وظيفة 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 ، نربط العرض بمتغيرات ونصف أنه عندما يتم تغيير النص في 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
اسمحوا لنا أن نعرف في التعليقات ما يمكن وصفه بمزيد من التفصيل.