Android JNI 開啓子線程後調用 Activity 方法更新UI

  • MainActivity 代碼
    點擊按鈕調用 native 方法,開啓線程,調用MainActivity 方法更新UI
class MainActivity : AppCompatActivity() {

    companion object {
        private const val TAG: String = "MainActivity";

        init {
            System.loadLibrary("native-lib")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

    }

    fun onClick(view: View) {
        useThread()
    }

    private external fun useThread();

    // AndroidUI操作,讓C++線程裏面來調用
    fun updateUI() {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            showDialog()
        } else {
            Log.d("MainActivity", Thread.currentThread().name)
            runOnUiThread {
                showDialog();
            }
        }
    }

    private fun showDialog() {
        AlertDialog.Builder(this@MainActivity)
            .setTitle("hello!!!")
            .setMessage("updateUI run ...")
            .setPositiveButton("確定", null)
            .show()
    }

}
  • native 方法 具體作用都在註釋裏面了
#include <jni.h>
#include <string>
#include <android/log.h>
#include <pthread.h>

#define TAG "ld"
#define log_debug(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__)
#define log_info(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)

jobject mainActivityObj;
JavaVM *jvm;

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *javaVm, void *pVoid) {
    // 獲取 javaVM
    jvm = javaVm;
    return JNI_VERSION_1_6;
}

void *customerThread(void *pVoid) {
    // JVM 是可以跨線程使用的
    // JNIEnv是不可以跨線程的 所以需要通過 JVM創建當前線程使用的 JNIEnv
    JNIEnv *env = nullptr;
    jint result = jvm->AttachCurrentThread(&env, 0);
    log_debug("創建env結果爲:%d", result);
    if (result != JNI_OK) {
        return 0;
    }
    // 獲取 MainActivity 的 jclass
    jclass mainActivityClass = env->GetObjectClass(mainActivityObj);
    const char *sig = "()V";
    jmethodID mainMethodId = env->GetMethodID(mainActivityClass, "updateUI", sig);
    // 調用 updateUI 方法
    env->CallVoidMethod(mainActivityObj, mainMethodId);
    // 解除線程 釋放掛在 JVM的native線程
    jvm->DetachCurrentThread();
    return 0;
};

// 入口
extern "C"
JNIEXPORT void JNICALL
Java_com_lu_jni_MainActivity_useThread(JNIEnv *env, jobject thiz) {
    // 必須創建一個 全局變量 來公用參數 如果是局部變量方法出棧後 對象將被釋放
    mainActivityObj = env->NewGlobalRef(thiz);
    // 定義 pthread_t 線程標識
    pthread_t pthreadID;
    // 創建線程  調用 customerThread 
    pthread_create(&pthreadID, 0, customerThread, mainActivityObj);
    // 用來等待一個線程的結束,線程間同步的操作
    pthread_join(pthreadID, 0);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章