2010-11-02 84 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电话,每个电话都将依次运行。