2010-11-02 86 views
4

我有一個C庫,可以通過NDK訪問。一些操作非常耗時,因此UI線程凍結了它們。正如我現在普遍的做法是使用Runnable的那樣:如何解決NDK庫調用凍結UI線程的問題

myFixedThreadPool.execute(new Runnable() 
{ 
    public void run() 
    { 
    NativeClass.callToNDKLibrary(); 
    }; 
}); 

或螺紋類似:

Thread t = new Thread() 
{ 
    public void run() 
    { 
    NativeClass.callToNDKLibrary(); 
    } 
}; 
t.start(); 

但問題是,C庫不是線程安全的:在啓動時崩潰我這樣包裹它。所以問題是如何從UI線程分離,仍然強制NDK調用一次運行一個。可能有一些與同步技巧將有助於?我也想提一下,這個庫是我的應用程序的核心底層,而不僅僅是一個輔助函數。所以它幾乎被我的代碼的每一部分調用。只有少數幾個函數會消耗時間,大多數函數都會將它們保留在主線程中。

回答

3

最終溶液如下:

  1. 定義所有JNI本地方法爲同步。這將防止C庫崩潰,但仍會凍結UI。
  2. 定義單一線程執行:

    ExecutorService的mExecutorThread = Executors.newSingleThreadExecutor();

  3. 包裝所有的時間在該線程耗時操作:

    mExecutorThread.execute(新的Runnable(){ 公共 無效的run(){ NativeClass。callToNDKLibrary(); } });

我不得不做的最後一件事是稍微重新設計我的代碼,以確保沒有任何本地方法從onDraw()調用。我在事件處理程序中緩存了本地方法的結果,並在onDraw()中使用了緩存的值。

2

但問題是,C庫不是線程安全的:它開始崩潰,當我這樣包裝它時。

然後對庫上的所有操作使用單個專用後臺線程。例如,使用IntentService訪問庫,其中調用startService()的活動將命令發送到IntentService

或者:

  1. 創建LinkedBlockingQueue<Job>,對於一些Job類/接口定義
  2. 有排隊
  3. 將作業發送到該隊列訪問磁帶庫
  4. 發送一個單獨的線程監控一個特殊的「kill job」到隊列中導致monitor-the-queue循環退出,從而導致後臺線程終止,一旦你不再需要隊列和線程

或者,花時間使庫在C級別線程安全。讓C代碼成爲線程安全的話題已經成爲大約20年的討論話題,所以可能有一些技巧可以用來體驗所有這些經驗。

+0

謝謝,它給了我一個線索從哪裏開始思考。 – 2010-11-16 22:52:00

0

您可以使用Looper創建消息循環。然後通過Handler傳遞你的NDK電話,每個電話都將依次運行。