How to solve the problem of NDK library calls freezing UI thread
I have a C library which I access through NDK. Some operations are time consuming so UI thread freezes on them. As I now the common practice is to use Runnable like that:
myFixedThreadPool.execute(new Runnable()
{
public void run()
{
NativeClass.callToNDKLibrary();
};
});
or threads like that:
Thread t = new Thread()
{
public void run()
{
NativeClass.callToNDKLibrary();
}
};
t.start();
but the problem is that C library is not thread safe: it starts to crash when开发者_开发问答 I wrap it like this. So the question is how to detach from UI thread still enforcing NDK calls to run one at a time. May be some trick with synchronized will help? I also want to mention that this library is a core underlying layer for my application, not just a helper function. So it's called from nearly every part of my code. And only a few functions consume time, most a quick to keep them in main thread.
The final solution is as follows:
- Define all JNI native methods as synchronized. This will prevent C library from crashing but still will freeze UI.
Define single thread executor:
ExecutorService mExecutorThread = Executors.newSingleThreadExecutor();
Wrap all time consuming operations in that thread:
mExecutorThread.execute(new Runnable() { public void run() { NativeClass.callToNDKLibrary(); } });
Last thing I had to do was to slightly redesign my code to make sure that none of native methods are called from onDraw(). I made the results of native methods cached in event handlers and used that cached values in onDraw().
but the problem is that C library is not thread safe: it starts to crash when I wrap it like this.
Then use a single dedicated background thread for all operations on the library. For example, use an IntentService
to access the library, with the activities calling startService() to send commands to the IntentService
.
Or:
- Create a
LinkedBlockingQueue<Job>
, for someJob
class/interface you define - Have a single thread monitor that queue
- Send jobs to that queue to access your library
- Send a special "kill job" to the queue to cause the monitor-the-queue loop to exit, causing the background thread to terminate, once you no longer need the queue and thread
Or, spend the time to make the library thread-safe at the C level. Making C code be thread-safe has been a topic of discussion for ~20 years, so there is probably some tricks you can use that have arisen from all that experience.
You could use a Looper
to create a message loop. Then pass your NDK calls in via a Handler
and each will be run in turn.
精彩评论