Implementasi Android (NDK) dari panggilan balik JNI, pola Observer- Pelanggan dengan NDK dan panggilan balik, EventBus atau Rx berpemilik
... Saya mengerti "tidak ada bagian yang dapat diperbaiki pengguna di dalam." Saya ingin melihat apa yang ada di sana.
- Boneka bersarang Rusia ke bagian paling dalam. Benarkah, Orozco? Juan tidak terlihat seperti boneka bersarang Rusia.
"Ini sampah, Profesor Gu." Siapa yang butuh - untuk mengacaukan ini?
"Akhir Pelangi" Vinge Vernor
Ada beberapa aplikasi Android yang menggabungkan kode C ++ dan Java. Java mengimplementasikan logika bisnis, dan C ++ melakukan semua pekerjaan komputasi, sering ditemukan dalam pemrosesan audio. Aliran audio diproses di suatu tempat di dalam, dan rem dengan gas dan kopling ditampilkan di lantai atas, dan data untuk semua jenis gambar lucu.
Nah, sejak ReactiveX, itu sudah akrab, agar tidak mengubah tangan Anda, dan bekerja dengan ruang bawah tanah JNI dengan cara yang akrab, Anda secara teratur perlu menerapkan pola Observer dalam proyek-proyek dengan NDK. Nah, pada saat yang sama, kelengkapan kode untuk arkeolog mereka yang kurang beruntung untuk "memahami kode orang lain" meningkat.
Jadi, cara terbaik untuk mempelajari sesuatu adalah dengan melakukannya sendiri.
Katakanlah kita suka dan tahu cara menulis sepeda motor kita. Dan apa yang akan kita dapatkan sebagai hasilnya:
- sesuatu seperti postback dari kode C ++ ke penandatangan;
- pengelolaan pemrosesan dalam kode asli, yaitu, kami mungkin tidak dipaksa masuk ke pemukiman ketika tidak ada pelanggan dan tidak ada yang mengirimnya;
- transfer data antara JVM yang berbeda mungkin diperlukan;
- dan agar tidak bangun dua kali, pada saat yang sama mengirim pesan di dalam proyek mengalir.
Kode kerja lengkap tersedia di GitHub . Artikel hanya memberikan kutipan darinya.
Sedikit teori dan sejarah
Baru-baru ini saya menghadiri pertemuan RX dan kagum pada sejumlah pertanyaan tentang: seberapa cepat ReactiveX dan bagaimana cara kerjanya sama sekali.
Untuk ReactiveX, saya hanya bisa mengatakan bahwa untuk Java kecepatannya sangat tergantung pada seberapa layak digunakan, jika digunakan dengan benar, kecepatannya sudah cukup.
Sepeda kami jauh lebih ringan, tetapi jika Anda perlu, misalnya, antrian pesan (seperti flowable), maka Anda perlu menulis sendiri. Karena Anda tahu bahwa semua gangguan hanya milik Anda.
Sedikit teori: pola Observer- Subscriber adalah mekanisme yang memungkinkan suatu objek menerima peringatan tentang perubahan dalam keadaan objek lain dan karenanya mengamati mereka. Hal ini dilakukan untuk mengurangi konektivitas dan ketergantungan antara komponen perangkat lunak, yang memungkinkan mereka untuk digunakan dan diuji lebih efisien. Perwakilan yang jelas di mana konsep bahasa dibangun di atas ini adalah segalanya - Smalltalk, semua didasarkan pada gagasan mengirim pesan. Objective-C yang Terkena Dampak
Implementasi
Mari kita coba dalam tradisi terbaik DIY, sehingga untuk berbicara, "berkedip LED". Jika Anda menggunakan JNI, di dunia Android NDK, Anda dapat meminta metode Java secara tidak sinkron, di utas apa pun. Inilah yang kami gunakan untuk membangun "Pengamat" kami.
Proyek demo didasarkan pada templat proyek baru dari Android Studio.
Ini adalah metode yang dibuat secara otomatis. Dia berkomentar:
Sekarang untuk dirimu sendiri. Langkah pertama adalah metode nsubscribeListener
.
private native void nsubscribeListener(JNIListener JNIListener);
Ini memungkinkan kode C ++ untuk mendapatkan tautan ke kode java untuk mengaktifkan panggilan balik ke objek yang mengimplementasikan antarmuka JNIListener.
public interface JNIListener { void onAcceptMessage(String string); void onAcceptMessageVal(int messVal); }
Nilai akan ditransfer ke implementasi metodenya.
Untuk caching tautan yang efektif ke mesin virtual, kami juga menyimpan tautan ke objek. Kami mendapatkan tautan global untuk itu.
Java_ua_zt_mezon_myjnacallbacktest_MainActivity_nsubscribeListener(JNIEnv *env, jobject instance, jobject listener) { env->GetJavaVM(&jvm);
Segera hitung dan simpan tautan ke metode. Ini berarti lebih sedikit operasi diperlukan untuk menyelesaikan panggilan balik.
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");
Data pelanggan disimpan sebagai catatan kelas ObserverChain
.
class ObserverChain { public: ObserverChain(jweak pJobject, jmethodID pID, jmethodID pJmethodID); jweak store_Wlistener=NULL; jmethodID store_method = NULL; jmethodID store_methodVAL = NULL; };
Simpan pelanggan ke array dinamis store_Wlistener_vector.
ObserverChain *tmpt = new ObserverChain(store_Wlistener, store_method, store_methodVAL); store_Wlistener_vector.push_back(tmpt);
Sekarang tentang bagaimana pesan dari kode Java akan dikirimkan.
Pesan yang dikirim ke metode nonNext akan dikirim ke semua penandatangan.
private native void nonNext(String message);
Implementasi:
Java_ua_zt_mezon_myjnacallbacktest_MainActivity_nonNext(JNIEnv *env, jobject instance, jstring message_) { txtCallback(env, message_); }
Fungsi txtCallback (env, message_); mengirim pesan ke semua penandatangan.
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_); } } }
Untuk meneruskan pesan dari C ++ atau kode C, kami menggunakan fungsi test_string_callback_fom_c
void test_string_callback_fom_c(char *val)
Dia memeriksa sejak awal jika ada pelanggan sama sekali.
if (store_Wlistener_vector.empty()) return;
Sangat mudah untuk melihat bahwa fungsi txtCallback yang sama digunakan untuk mengirim pesan:
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; }
Di MainActivity kami membuat dua tampilan teks dan satu 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" />
Di OnCreate, kami mengikat Lihat dengan variabel dan menjelaskan bahwa ketika teks diubah di EditText, pesan akan dikirim ke pelanggan.
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);
Kami memulai dan mendaftarkan pelanggan:
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);
Itu terlihat seperti ini:

Kode kerja lengkap tersedia di GitHub https://github.com/NickZt/MyJNACallbackTest
Beri tahu kami di komentar apa yang harus dijelaskan secara lebih rinci.