Android JNI開發-實際項目開發總結(回調函數)

這篇文章想要介紹一下我以前作的一個真實項目,感受比較有意思,記錄一下。java

項目介紹

這個項目比較有特色的是項目的主要業務邏輯由C語言開發同事完成,在他的SO庫中去作初始化、網絡操做、數據庫存儲、硬件設備操做等等的邏輯,我這邊Android主要就是調用他的接口結合界面完成業務。git

可是因爲咱們在第三方硬件設備操做,而第三方只提供了Android的SDK,在C層面沒法調用,因此硬件操做的接口也須要由我進行封裝,提供操做的接口(回調函數,不瞭解的請看這裏)給C開發同事調用。這樣就造成了下面的結構:github

我在APP初始化的時候,就將全部有關界面操做和硬件操做的函數以參數的形式傳給SO。SO庫中實際業務中,若是須要修改界面,好比要顯示黑名單下載進度,就調用傳入downloadBlackListCallBack函數,這個函數中會以JNI反射的方式調用到Java層代碼,再由Java層代碼實現進度的更新。硬件操做接口一樣的道理。數據庫

代碼實現

SO庫函數定義

在一步中除了正常的參數傳入,重要的就是傳入回調函數了。markdown

和同事作好協商,以顯示進度爲例,在SO庫對外提供的函數中有這樣一個函數,用來設置進度回調。網絡

void APi_SetProgressCallback(Processfun Callback);
複製代碼

在他的頭文件中Processfun的定義以下,要求咱們傳入兩個int類型的值,第一個參數爲已下載數量,第二個參數爲總數量。jvm

typedef void (*Processfun)(int,int);
複製代碼

這個是SO庫中要求的函數形式,接下來咱們就要寫本身的實現函數函數

Java層實現

咱們首先實現一個Java層真正去控制進度顯示的函數。oop

在JNIController類中實現函數:spa

/** * 黑名單下載進度展現 * * @param downloaded 已下載黑名單條數 * @param all 總黑名單條數 */

    private void downloadBlackListCallBack(int downloaded, int all) {
        Intent intent = new Intent();
        intent.setAction(DOWNLOAD_BLACKLIST_ACTION);
        intent.putExtra(BLACKLIST_DOWNLOADED, downloaded);
        intent.putExtra(BLACKLIST_ALL, all);
        Application.getInstance().sendBroadcast(intent);
    }
複製代碼

入參和上面定義的同樣,已下載數量和總數量,當函數調用後經過廣播的方式將傳入的數量發送出去,廣播接收器去修改界面。

JNI層實現

而後要從JNI層以反射的方式調用Java層的downloadBlackListCallBack函數。

void downloadBlackListCallBack(int downloaded, int all);

void downloadBlackListCallBack(int downloaded, int all) {
    JNIEnv *env = NULL;
    int status = (*local_jvm)->AttachCurrentThread(local_jvm, &env, NULL);

    if (status < 0) {
        LOGD("env is null");
        return;
    }

    jclass jclass1 = (*env)->FindClass(env, "com/.../controller/JNIController");
    if (jclass1 == 0) {
        LOGD("jclass1 = 0");
        return;
    }

    jmethodID downloadProcess = (*env)->GetMethodID(env, jclass1, "downloadBlackListCallBack",
                                                    "(II)V");
    if (downloadProcess == 0) {
        LOGD("methodID == 0");
        return;
    }

    //調用Java層,downloaded, all參數傳入
    (*env)->CallVoidMethod(env, local_object, downloadProcess, downloaded, all);
  
    (*env)->DeleteLocalRef(env, jclass1);
}
複製代碼

在JNI中入參也是一致的形式,再經過反射的方式調用Java層代碼,將downloaded, all參數傳給Java函數。

傳遞函數

JNI層的downloadBlackListCallBack函數已經寫好了,最後就在初始化的函數中,調用SO庫提供的APi_SetProgressCallback(Processfun Callback)將函數以參數的形式傳入

APi_SetProgressCallback(downloadBlackListCallBack);
複製代碼
Processfun processFun = null;
  
void APi_SetProgressCallback(Processfun Callback){
		if(Callback!=NULL){
				processFun = Callback;
		}	
}

//業務代碼中
processFun(10,100);
複製代碼

這樣就是一個完整的流程了。

設備的硬件操做接口也是一樣的邏輯完成。

總結

總體而言,主要仍是用了C語言回調函數的方式,將上層的操做封裝成接口,交給底層邏輯本身控制,這樣比較靈活,雙方的代碼量也減小,就是須要在前期雙方梳理好須要的接口,完工!

相關文章
相關標籤/搜索