簡體   English   中英

在Android上從Java調用C ++類方法或函數,而無需在每次調用時重新創建類/變量

[英]Call C++ class methods or function from Java on android without recreating class/variable on every call

我有一個非常復雜的NLP代碼編寫在C ++上,現在我想從我的Android應用程序中使用它。 我的想法是使用客戶端 - 服務器架構構建應用程序,其中客戶端是android java應用程序,服務器是C ++面向對象的代碼。 但對我來說主要的問題是C ++組件非常繁重(標記器,矢量化器,語料庫數據等)並且我不能在每次調用時重新創建它們,我需要的是創建它們一次(在第一次請求時),然后將它們放在內存中,當應用程序處於活動狀態時,來自java端的handlind請求。

你能不能給我一些如何實現這一點的指導,因為我之前從未使用過Android的C ++? 提前致謝。


Java和C ++代碼不是遠程的,沒有涉及http或其他遠程請求,它是相同的應用程序。 但是為了減少Java / C ++通信間的開銷,我NlpEngine.sendRequest(string textToProcess, int processingWorkflowId)在java代碼中有單點聯系,比如NlpEngine.sendRequest(string textToProcess, int processingWorkflowId) ,然后是基於processingWorkflowId識別的C ++代碼,它是什么呢應該用文字。

Assumtion

我假設您使用Android NDK等工具集為Android編譯了C ++代碼,並且前端Java應用程序與后端C ++代碼在同一設備上運行。

Java本機調用和會話狀態

無論您使用以下三個接口中的哪一個。 加載C / C ++庫並在Java應用程序運行的整個時間內保留在內存中。 圖書館的狀態將一直保存。 我沒有清楚地了解你對初始化的擔憂。 這不像在CLI上啟動命令,其他應用程序一次又一次地啟動和停止。

...但對我來說主要問題是C ++組件非常繁重(標記器,矢量化器,語料庫數據等),我不能在每次調用時重新創建它們......

用Java加載本機庫

有一些方法可以用Java加載本機庫,我想指出三點:

  • JNI - Java Native Interface

    JNI是一個與Java本身一樣古老的工具。 來自SWT的系統調用是使用JNI創建的。 JNI不是簡單的方法,您必須將要在Java中創建的函數/方法定義為本機,將它們編譯為C / C ++標頭,編寫用於在此中間庫中調用庫的代碼。 為每個ABI平台編譯此代碼( 根據NDK,有7個Androids ABI )。 在Java程序中,您找到了調用ABI合適的中間庫的平台。 JNI還有許多其他陷阱。

  • JNA - Java Native Access

    [JNA]是一個通過反射動態加載C / C ++庫的java庫。 Java調用的定義是在純Java中完成的,沒有額外的工具。 易用性在性能上有所折衷,調用函數的開銷比JNI慢10倍。 但是,如果你經常調用極短的C / C ++庫函數/方法,那只會起作用。 在你的情況下,聽起來你只需要調用一些函數,這些函數將需要時間來運行。 JNA由Android開發人員使用。

  • JNR-FFI - Java Native Runtime

    JNR-FFI是最新的候選人。 JNR-FFI是用於調用庫的部分。其他部分是JNR-FFI的基線。 它受到JNA的啟發。 使用JNA和JNR-FFI開發的Java代碼看起來非常相似。 JNR-FFI開發的原因是性能。 一般來說,JNR-FFI比JNI慢一點(對於getpid大約15%)但在某些情況下它可能比JNI快。 對於C / C ++端的長運行時,這種開銷並不重要。 JNR被提議在Java 9中作為標准庫JEP 191:外部函數接口 警告:JNR-FFI接縫與Android有一些問題。

個人經驗

我不得不從Java實現一些本機庫調用。 我從JNI開始,經過一周的測試研究后,只有很少的演示線有效。 每次嘗試都需要很長時間,不同的工具,很長的建設時間。 我找到了關於JNI陷阱的演示文稿以及必須考慮的副作用。 ...

我找到了JNA。 在幾個小時內,我的庫的第一個演示代碼工作,並與JNI相比,它是如此輕量級和快速開發。 我切換到JNR-FFI,因為它是JNA的現代版本。 對於我所做的,性能不是切換的原因,這只是一個積極的副作用。

我沒有在Android下用JNA或JNR-FFI開發。 但在你的情況下,我會嘗試JNA,因為它更好地支持Android。 我希望JNR-FFI能夠在Java 9中實現,從JNA代碼切換到JNR-FFI代碼很容易。

我添加了JNR-FFI的示例,讓您了解易用性。 除了實現這幾行以便能夠調用本機c庫函數之外,沒有什么比這更多的了。

JNR-FFI取自Java Native Runtime的例子- Charles Oliver Nutter的Missing Link

public class GetPidJNRExample {
    public interface GetPid {
        @IgnoreError
        long getpid();
    }

    public static void main( String[] args ) {
        LibraryLoader<GetPid> loader =
            FFIProvider
                .getSystemProvider()
                .createLibraryLoader(GetPid.class);

        GetPid getpid = loader.load("c");

        getpid.getpid();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM